模拟法

题一:

题目描述:

力扣链接🔗

模拟法 - 图1

题目分析:

而求解本题依然是要坚持循环不变量原则

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去。

可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是一进循环深似海,从此offer是路人

这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开又闭的原则,这样这一圈才能按照统一的规则画下来。

那么我按照左闭右开的原则,来画一圈,大家看一下:

模拟法 - 图2

这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。

这也是坚持了每条边左闭右开的原则。

代码:

  1. class Solution {
  2. public int[][] generateMatrix(int n) {
  3. int[][] res = new int[n][n];
  4. int mid = n / 2; // 表格中间的数字,例如:n为5,此时中心就为[2,2]
  5. int count = 1; // 开始遍历的数字
  6. int offset = 1; // 偏移量
  7. int loop = n / 2; // 循环的圈树,例如:n为3,此时就只需要循环1圈
  8. int startX = 0, startY = 0; // 开始遍历的位置
  9. // 以下四个循环代表遍历一圈,此时都遵循左闭右开来遍历
  10. while (loop > 0) {
  11. int i = startY, j = startX;
  12. // 遍历上边
  13. for (; j < startX + n - offset; j++) {
  14. res[i][j] = count++;
  15. }
  16. // 遍历右边
  17. for (; i < startY + n - offset; i++) {
  18. res[i][j] = count++;
  19. }
  20. // 遍历下边
  21. for (; j > startX; j--) {
  22. res[i][j] = count++;
  23. }
  24. // 遍历左边
  25. for (; i > startY; i--) {
  26. res[i][j] = count++;
  27. }
  28. // 将起始位置加一
  29. startX++;
  30. startY++;
  31. // 将循环圈数减一
  32. loop--;
  33. // 将偏移量加二,因为边界多了2条
  34. offset += 2;
  35. }
  36. // 如果n为奇数,将中心赋值
  37. if (n % 2 == 1) {
  38. res[mid][mid] = count;
  39. }
  40. return res;
  41. }
  42. }

题二:

题目描述:

力扣链接🔗

模拟法 - 图3

题目分析:

此时不是标准的正方形,此时使用层数来遍历会遇到许多判断,此时可以按层模拟,可以将矩阵看成若干层,首先输出最外层的元素,其次输出次外层的元素,直到输出最内层的元素。

定义矩阵的第 k 层是到最近边界距离为 k 的所有顶点。例如,下图矩阵最外层元素都是第 1 层,次外层元素都是第 2 层,剩下的元素都是第 3 层。

  1. [[1, 1, 1, 1, 1, 1, 1],
  2. [1, 2, 2, 2, 2, 2, 1],
  3. [1, 2, 3, 3, 3, 2, 1],
  4. [1, 2, 2, 2, 2, 2, 1],
  5. [1, 1, 1, 1, 1, 1, 1]]

模拟法 - 图4

按照如下路径遍历:

模拟法 - 图5

代码:

  1. class Solution {
  2. public List<Integer> spiralOrder(int[][] matrix) {
  3. List<Integer> list = new ArrayList<Integer>();
  4. // 为空判断
  5. if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
  6. return list;
  7. }
  8. int rows = matrix.length, columns = matrix[0].length;
  9. int top = 0, button = rows - 1, right = columns - 1, left = 0; // 代表上下左右
  10. while (left <= right && top <= button) {
  11. // 遍历上边
  12. for (int column = left; column <= right; column++) {
  13. list.add(matrix[top][column]);
  14. }
  15. // 遍历右边
  16. for (int row = top + 1; row <= button; row++) {
  17. list.add(matrix[row][right]);
  18. }
  19. // 注意此时没有判断等于,注意左下角和右上角的不同
  20. if (left < right && top < button) {
  21. for (int column = right - 1; column > left; column--) {
  22. list.add(matrix[button][column]);
  23. }
  24. for (int row = button; row > top; row--) {
  25. list.add(matrix[row][left]);
  26. }
  27. }
  28. left++;
  29. right--;
  30. top++;
  31. button--;
  32. }
  33. return list;
  34. }
  35. }

题三:

题目描述:

力扣链接🔗

模拟法 - 图6

题目分析:

此题和与上一题模拟方法一致,按照如下路径遍历。

模拟法 - 图7

代码:

  1. class Solution {
  2. public int[] spiralOrder(int[][] matrix) {
  3. if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
  4. return new int[]{};
  5. }
  6. List<Integer> list = new ArrayList<>();
  7. int rows = matrix.length, columns = matrix[0].length; // 行列的数量
  8. int top = 0, button = rows - 1, right = columns - 1, left = 0;
  9. while (left <= right && top <= button) {
  10. // 遍历上边
  11. for (int column = left; column <= right; column++) {
  12. list.add(matrix[top][column]);
  13. }
  14. // 遍历右边
  15. for (int row = top + 1; row <= button; row++) {
  16. list.add(matrix[row][right]);
  17. }
  18. if (left < right && top < button) {
  19. // 遍历下边
  20. for (int column = right - 1; column > left; column--) {
  21. list.add(matrix[button][column]);
  22. }
  23. // 遍历左边
  24. for (int row = button; row > top; row--) {
  25. list.add(matrix[row][left]);
  26. }
  27. }
  28. left++;
  29. right--;
  30. top++;
  31. button--;
  32. }
  33. int[] ints = new int[list.size()];
  34. for (int i = 0; i < list.size(); i++) {
  35. ints[i] = list.get(i);
  36. }
  37. return ints;
  38. }
  39. }