【二刷代码随想录】螺旋矩阵求解方法、推荐习题

发布于:2025-03-30 ⋅ 阅读:(55) ⋅ 点赞:(0)

一、求解方法 

(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 ---> right
            for(int j = left; j <= right; j++){
                res[top][j] = num++;
            }
            top++;

            //右:从上到下-----i 从 top ---> bottom
            for(int i = top; i <= bottom; i++){
                res[i][right] = num++;
            }
            right--;

            if(top <= bottom){
                //下:从右到左-----j 从 right ---> left
                for(int j = right; j >= left; j--){
                    res[bottom][j] = num++;
                }
                bottom--;
            }
            

            if(left <= right){
                //左:从下到上-----i 从 bottom ---> top
                for(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-offset
            for(j = yStart; j < n-offset; j++){
                res[xStart][j] = num++;
            }

            //右:从上到下-----i 从 xStart ---> n-offset
            for(i = xStart; i < n-offset; i++){
                res[i][j] = num++;
            }

            //下:从右到左-----j 递减到 yStart+1
            for(; j > yStart; j--){
                res[i][j] = num++;
            }

            //左:从下到上-----i 递减到 xStart+1
            for(; 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;
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到