一、求解方法
(1)按点模拟路径
在原有坐标的基准上,叠加 横纵坐标 的变化值,求出下一位置,并按题完成要求。但需注意转角的时机判断,特别是最后即将返回上一出发点的位置。
(2)按层模拟路径
在原有的形状基础上,画出 上下左右 四根边界线,按照顺序完成画圈。但需要关注单行或单列可能存在重复的情况,因此需在操作 下 和 左 边界线时加上判定条件。
(3)心路历程
最开始掌握的是 Carl 教的循环画框类的思路,但是它的应用是在方形样式,其中的 offset 和 中间元素处理对于方形图案比较好处理,但是针对矩形样式,我真的不知道要怎么改了。后改学其他思路,也就是上述两种。
二、推荐例题
(1)方形样式的螺旋矩阵
59. 螺旋矩阵 II
方法1:点模拟
class Solution {public int[][] generateMatrix(int n) { int curNum = 1;int maxNum = n * n;int curRow = 0;int curCol = 0;int dirIndex = 0;int[][] dirs = {{0,1}, {1,0}, {0,-1}, {-1,0}};int[][] res = new int[n][n];while(curNum <= maxNum){res[curRow][curCol] = curNum++;//判定后续位置是否越界int nextRow = curRow + dirs[dirIndex][0];int nextCol = curCol + dirs[dirIndex][1];//需要加一个res[nextRow][nextCol] != 0 因为走了一圈之后就回到了原点,需要避免回原点,而是调整方向//比如三阶矩阵中的最后9,若不调整方向,则会放到原点处if(nextRow < 0 || nextRow > n-1 || nextCol < 0 || nextCol > n-1 || res[nextRow][nextCol] != 0){dirIndex = (dirIndex+1) % 4;}curRow = curRow + dirs[dirIndex][0];curCol = curCol + dirs[dirIndex][1];}return res;}
}
方法2:层模拟
class Solution {public int[][] generateMatrix(int n) { int left = 0;int right = n-1;int top = 0;int bottom = n-1;int num = 1;int[][] res = new int[n][n];while(left <= right && top <= bottom){//上:从左往右-----j 从 left ---> rightfor(int j = left; j <= right; j++){res[top][j] = num++;}top++;//右:从上到下-----i 从 top ---> bottomfor(int i = top; i <= bottom; i++){res[i][right] = num++;}right--;if(top <= bottom){//下:从右到左-----j 从 right ---> leftfor(int j = right; j >= left; j--){res[bottom][j] = num++;}bottom--;}if(left <= right){//左:从下到上-----i 从 bottom ---> topfor(int i = bottom; i >= top; i--){res[i][left] = num++;}left++;}}return res;}
}
方法3:“循环画框”
class Solution {public int[][] generateMatrix(int n) { int loopCur = 1; //当前所处的圈数int loopCnt = n / 2; //所需绘制的完整圈数int xStart = 0; //横坐标的开始坐标int yStart = 0; //纵坐标的开始坐标int offset = 1; //当前绘制圈的偏置值int num = 1; //当前绘制的数字int i,j; //绘制地图用的横纵坐标int[][] res = new int[n][n];while(loopCur <= loopCnt){//上:从左往右-----j 从 yStart ---> n-offsetfor(j = yStart; j < n-offset; j++){res[xStart][j] = num++;}//右:从上到下-----i 从 xStart ---> n-offsetfor(i = xStart; i < n-offset; i++){res[i][j] = num++;}//下:从右到左-----j 递减到 yStart+1for(; j > yStart; j--){res[i][j] = num++;}//左:从下到上-----i 递减到 xStart+1for(; i > xStart; i--){res[i][j] = num++;}offset++; //调整偏置值loopCur++;xStart++;yStart++;}if(1 == n%2){res[xStart][yStart] = num;}return res;}
}
(2)矩形样式的螺旋矩阵
54.螺旋矩阵
方法1:点模拟
class Solution {public List<Integer> spiralOrder(int[][] matrix) {List<Integer> res = new ArrayList<Integer>();if(matrix == null){return res;}int rows = matrix.length;int cols = matrix[0].length;int cnt = rows * cols;if (rows == 0 || cols == 0) {return res;}int curRow = 0;int curCol = 0;int dirIndex = 0;int[][] dirs = {{0,1}, {1,0}, {0,-1}, {-1,0}};boolean[][] visited = new boolean[rows][cols];while(cnt > 0){res.add(matrix[curRow][curCol]);visited[curRow][curCol] = true;//判定后续位置是否越界int nextRow = curRow + dirs[dirIndex][0];int nextCol = curCol + dirs[dirIndex][1];//需要加一个res[nextRow][nextCol] != 0 因为走了一圈之后就回到了原点,需要避免回原点,而是调整方向//比如三阶矩阵中的最后9,若不调整方向,则会放到原点处if(nextRow < 0 || nextRow > rows-1 || nextCol < 0 || nextCol > cols-1 || visited[nextRow][nextCol] != false){dirIndex = (dirIndex+1) % 4;}curRow = curRow + dirs[dirIndex][0];curCol = curCol + dirs[dirIndex][1];cnt--;}return res;}
}
方法2:层模拟
class Solution {public List<Integer> spiralOrder(int[][] matrix) {List<Integer> res = new ArrayList<Integer>();if(matrix == null){return res;}int rows = matrix.length;int cols = matrix[0].length;if (rows == 0 || cols == 0) {return res;}int top = 0;int bottom = rows -1;int left = 0;int right = cols -1;while(top <= bottom && left <= right){//上:从左到右for(int j = left; j <= right; j++){res.add(matrix[top][j]);}top++;//右:从上到下for(int i = top; i <= bottom; i++){res.add(matrix[i][right]);}right--;//下:从右到左if(top <= bottom){ //若不判断,遇见单行,则会重复处理for(int j = right; j >= left;j--){res.add(matrix[bottom][j]);}}bottom--;//左:从下到上if(left <= right){ //若不判断,遇见单列,则会重复处理for(int i = bottom; i >= top; i--){res.add(matrix[i][left]);}}left++;}return res;}
}
方法3: “循环画框”--错误代码演示,没改出来
class Solution {public List<Integer> spiralOrder(int[][] matrix) {List<Integer> res = new ArrayList<Integer>();int rows = matrix.length;int cols = matrix[0].length;int loopCur = 1;int loopCnt = rows/2 + 1; //为便捷处理中心区域的多个数据int xStart = 0;int yStart = 0;int offset = 1;//因为增加了圈数,导致单行的矩阵会重复打印if(rows == 1){for(int temp = 0; temp < cols; temp++){res.add(Integer.valueOf(matrix[0][temp]));}return res;}//因为增加了圈数,导致单列的矩阵会重复打印if(cols == 1){for(int temp = 0; temp < rows; temp++){res.add(Integer.valueOf(matrix[temp][0]));}return res;}int i,j;while(loopCur <= loopCnt){//上:从左到右for(j = yStart; j < cols-offset; j++){res.add(matrix[xStart][j]); }//右:从上到下for(i = xStart; i < rows-offset; i++){res.add(matrix[i][j]);}//下:从右到左for(; j > yStart; j--){res.add(matrix[i][j]);}//左:从下到上for(; i > xStart; i--){res.add(matrix[i][j]);}offset++;loopCur++;xStart++;yStart++;}if(rows == cols && rows%2 ==1){res.add(matrix[xStart-1][yStart-1]);}return res;}
}