54.螺旋矩阵

 

给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素

示例 1:

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

 示例 2:

输入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]

 一、初解思路:

m行n列的数组,循环的话完整的圈数有m、n中最小值的一半,是否有不完整的循环靠对2取余得到,将遍历分为→↓←↑四趟,这四趟的坐标移动规律靠画图很容易整理出:

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List list = new ArrayList<Integer>();
        if(matrix == null || matrix.length == 0) {
            return list;
        }
        int q = 0;
        int m = matrix.length;
        int n = matrix[0].length;
        if(m < n) {
            q = m / 2 + m % 2 ;
        } else {
            q = n / 2 + n % 2 ;
        }
        
        for(int i = 0 ; i < q ; i++) {
            for(int a = i; a < n - i; a++) {
                list.add(matrix[i][a]);
            }
            for(int b = i + 1; b < m - i; b ++) {
                list.add(matrix[b][n-1-i]);
            }
            for(int c = n - 2 -i; c >= i && i * 2 + 1 < m; c--) {
                list.add(matrix[m-1-i][c]);
            }
            for(int d = m - 2- i; d >= i+1 && i * 2 + 1 < n; d--) {
                list.add(matrix[d][i]);
            }

        }
        return list;
    }
}

二、模拟:

模拟数组螺旋遍历的过程,使用dr、dc分别表示右下左上螺旋循环时x/y坐标移动的增量,然后循环比例,一但走到数组边界,或者下个元素已经被遍历过了,则更换方向,继续遍历。

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List ans = new ArrayList();
        if (matrix.length == 0) return ans;
        int R = matrix.length, C = matrix[0].length;
        boolean[][] seen = new boolean[R][C];
        int[] dr = {0, 1, 0, -1};
        int[] dc = {1, 0, -1, 0};
        int r = 0, c = 0, di = 0;
        for (int i = 0; i < R * C; i++) {
            ans.add(matrix[r][c]);
            seen[r][c] = true;
            int cr = r + dr[di];
            int cc = c + dc[di];
            if (0 <= cr && cr < R && 0 <= cc && cc < C && !seen[cr][cc]){
                r = cr;
                c = cc;
            } else {
                di = (di + 1) % 4;
                r += dr[di];
                c += dc[di];
            }
        }
        return ans;
    }
}

时间复杂度: O(N),其中 N 是输入矩阵所有元素的个数。因为我们将矩阵中的每个元素都添加进答案里。
空间复杂度: O(N),需要两个矩阵 seen 和 ans 存储所需信息。

三、按层模拟

方法和上边的思路一样,换了实现

class Solution {
    public List < Integer > spiralOrder(int[][] matrix) {
        List ans = new ArrayList();
        if (matrix.length == 0)
            return ans;
        int r1 = 0, r2 = matrix.length - 1;
        int c1 = 0, c2 = matrix[0].length - 1;
        while (r1 <= r2 && c1 <= c2) {
            for (int c = c1; c <= c2; c++) ans.add(matrix[r1][c]);
            for (int r = r1 + 1; r <= r2; r++) ans.add(matrix[r][c2]);
            if (r1 < r2 && c1 < c2) {
                for (int c = c2 - 1; c > c1; c--) ans.add(matrix[r2][c]);
                for (int r = r2; r > r1; r--) ans.add(matrix[r][c1]);
            }
            r1++;
            r2--;
            c1++;
            c2--;
        }
        return ans;
    }
}

时间、空间复杂度O(N)

四、旋转数组

读取第一行,然后旋转剩下的数组,直到数组被裁减没

五、其他的实现方式

首先设定上下左右边界
其次向右移动到最右,此时第一行因为已经使用过了,可以将其从图中删去,体现在代码中就是重新定义上边界
判断若重新定义后,上下边界交错,表明螺旋矩阵遍历结束,跳出循环,返回答案
若上下边界不交错,则遍历还未结束,接着向下向左向上移动,操作过程与第一,二步同理
不断循环以上步骤,直到某两条边界交错,跳出循环,返回答案

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector <int> ans;
        if(matrix.empty()) return ans; //若数组为空,直接返回答案
        int u = 0; //赋值上下左右边界
        int d = matrix.size() - 1;
        int l = 0;
        int r = matrix[0].size() - 1;
        while(true)
        {
            for(int i = l; i <= r; ++i) ans.push_back(matrix[u][i]); //向右移动直到最右
            if(++ u > d) break; //重新设定上边界,若上边界大于下边界,则遍历遍历完成,下同
            for(int i = u; i <= d; ++i) ans.push_back(matrix[i][r]); //向下
            if(-- r < l) break; //重新设定有边界
            for(int i = r; i >= l; --i) ans.push_back(matrix[d][i]); //向左
            if(-- d < u) break; //重新设定下边界
            for(int i = d; i >= u; --i) ans.push_back(matrix[i][l]); //向上
            if(++ l > r) break; //重新设定左边界
        }
        return ans;
    }
};

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值