LeetCode 54. 螺旋矩阵

114 阅读2分钟

题目描述:
给你一个m行n列的矩阵matrix,请按照顺时针螺旋顺序,返回矩阵中的所有元素。

示例 1:

截屏2022-07-09 下午1.33.13.png

输入: matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出: [1,2,3,6,9,8,7,4,5]

方法一:模拟

可以模拟螺旋矩阵的路径。初始位置是矩阵的左上角,初始方向是向右,当路径超出界限或者进入之前访问过的位置时,顺时针旋转,进入下一个方向。

判断路径是否进入之前访问过的位置需要使用一个与输入矩阵大小相同的辅助矩阵 visited,其中的每个元素表示该位置是否被访问过。当一个元素被访问时,将 visited 中的对应位置的元素设为已访问。

如何判断路径是否结束?由于矩阵中的每个元素都被访问一次,因此路径的长度即为矩阵中的元素数量,当路径的长度达到矩阵中的元素数量时即为完整路径,将该路径返回。

我觉得这道题的难点就在于我们什么时候需要进行转变方向,目前看转变方向分两种情况。第一种情况是遍历第一圈时,我们可以使用矩阵的长宽来判断。第二种情况是第二圈、第三圈...我们可以使用辅助矩阵 visited 来判断。

/**
 * 螺旋矩阵
 *
 * @author songjian
 * @link {https://leetcode.cn/problems/spiral-matrix/}
 */
public class SpiralOrder {
    public List<Integer> spiralOrder(int[][] matrix) {
        // 结果数组 (我的个人建议,写算法时方法有返回体时,尽量命名resObject)
        List<Integer> resArr = new ArrayList<>();
        // 入参数校验
        if (matrix == null || 0 == matrix.length || 0 == matrix[0].length) {
            return resArr;
        }

        int matrixRow = matrix.length;
        int matrixCol = matrix[0].length;

        // 辅助矩阵-用于判断当前位置是否遍历过
        boolean[][] visited = new boolean[matrixRow][matrixCol];
        // 用于判断矩阵遍历是否结束
        int total = matrixRow * matrixCol;
        // 当前位置
        int curRow = 0, curColumn = 0;
        // 顺时针方向(右、下、左、上)
        int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
        // 用于判断当前选择哪个方向 0->{0, 1}
        int directionIndex = 0;

        // 遍历矩阵
        for (int i = 0; i < total; i++) {
            resArr.add(matrix[curRow][curColumn]);
            // 标记已经走过该位置
            visited[curRow][curColumn] = true;
            // 移动以后所在的行
            int nextRow = curRow + directions[directionIndex][0];
            // 移动以后所在的列
            int nextCol = curColumn + directions[directionIndex][1];
            // 边缘校验 & 是否遍历
            if (nextRow < 0 || nextRow >= matrixRow ||
                    nextCol < 0 || nextCol >= matrixCol ||
                    visited[nextRow][nextCol]) {
                directionIndex = (directionIndex + 1) % 4;
            }
            // 移动
            curRow = curRow + directions[directionIndex][0];
            curColumn = curColumn + directions[directionIndex][1];
        }
        return resArr;
    }
}

这道题是我面试字节跳动第四面时的算法题,不过当时面试官要求空间复杂度保证在O(1),当时没有coding出来,有一点思路但是不多,现在复盘一下。

这种方式实在是太清晰了,就不写思路了,大家直接看代码吧:

public List<Integer> spiralOrderII(int[][] matrix) {
    // 结果数组
    ArrayList<Integer> resArr = new ArrayList<>();
    // 入参数校验
    if (matrix == null || 0 == matrix.length || 0 == matrix[0].length) {
        return resArr;
    }
    // 边界
    int left = 0;
    int right = matrix[0].length - 1;
    int top = 0;
    int bottom = matrix.length - 1;
    // 用于判断矩阵遍历是否结束
    int total = matrix[0].length * matrix.length;
    // 遍历矩阵
    while (total >= 1){
        // 右移
        for (int i = left; i <= right && total >= 1; i++) {
            resArr.add(matrix[top][i]);
            total--;
        }
        top++;

        // 下移
        for (int i = top; i <= bottom && total >= 1; i++) {
            resArr.add(matrix[i][right]);
            total--;
        }
        right--;

        // 左移
        for (int i = right; i >= left && total >= 1; i--) {
            resArr.add(matrix[bottom][i]);
            total--;
        }
        bottom--;

        // 上移
        for (int i = bottom; i >= top && total >= 1; i--) {
            resArr.add(matrix[i][left]);
            total--;
        }
        left++;
    }
    return resArr;
}

但是让我不理解的是,为什么leetCode上面的执行结果,我的内存消耗39.9M啊?
截屏2022-07-09 下午4.04.26.png 有没有人帮我解释一下,为什我的内存使用这么大?我不能接受啊!