剑指Offer29.顺时针打印矩阵

  • 剑指Offer29.顺时针打印矩阵

  • 题目:
    将一个矩阵的值顺时针打印到一个数组中;
    第一个方向是👉;

  • 思路:
    1.缩减边界法:O(mn):m和n分别是矩阵的长和宽,需要遍历完矩阵的每一个位置即m*n,O(1):只用到了几个常数变量;
    上下左右四个边界决定一个矩阵大小;
    按👉👇👈👆的顺序,每遍历完一个方向,缩减响应的边界;
    每个方向都能作为最后一个结束遍历的方向,因此每个方向结束都要判断是否结束;

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if (!matrix.size() || !matrix[0].size()) return {};
        
        vector<int> res;
        int m = matrix.size();
        int n = matrix[0].size();
        int l = 0, r = n - 1;//左右边界
        int up = 0, down = m - 1;//上下边界
        
        while (1) { //可能从任意方向退出,因此每个方向结束后都应该判断
            for (int i = l; i <= r; ++i) {// →
                res.push_back(matrix[up][i]);
            }
            if (++up > down) break;
            
            for (int i = up; i <= down; ++i) {//↓
                res.push_back(matrix[i][r]);
            }
            if (l > --r) break;
            
            for (int i = r; i >= l; --i) {//←
                res.push_back(matrix[down][i]);
            }
            if (up > --down) break;
            
            for (int i = down; i >= up; --i) {//↑
                res.push_back(matrix[i][l]);
            }
            if (++l > r) break;
        }
        
        return res;
    }
};

2.提前定义四个方向:O(mn):遍历矩阵的每个位置,O(mn):额外需要一个mn的矩阵visted标记走过的位置
虽然耗费空间大一些,但思路更清晰,且不容易错:① 结束条件由for循环条件 i < m
n 控制 ②四个方向由数组控制,无需挨着手动描述四个方向,且更灵活,例如题目改成逆时针,则只需修改方向数组dx和dy即可,而方法1需要全部重新写;

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if (!matrix.size() || !matrix[0].size()) return {};
        
        vector<int> res;
        int m = matrix.size();
        int n = matrix[0].size();
        vector<vector<bool>> visted(m, vector<bool>(n, false));//用来标记走过的格子
        int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};//右下左上
        int direction = 0; //初始方向:右
        int x = 0, y = 0; //初始位置[0, 0]
        for (int i = 0; i < m * n; ++i) { //共需遍历m*n个位置
            res.push_back(matrix[x][y]);
            visted[x][y] = true;//走过就标记

            int newX = x + dx[direction], newY = y + dy[direction];//下一位置
            if (newX < 0 || newX >= m || newY < 0 || newY >= n || visted[newX][newY]) {//若出界了或者走过了就换个方向
                direction = (direction + 1) % 4;//四个方向循环使用
                newX = x + dx[direction], newY = y + dy[direction];//换个方向一定能走,因为要把m*n个位置走完,既然能进入这层for循环,说明格子还没走完
            }
            x = newX, y = newY;//真正的下一位置; 
        }
        return res;
    }
};
  • 总结:
    两种方法各有优劣,要多多尝试使用方法2
    resize和reserve的区别:resize调整last,而reserve调整end_of_storage;res[cnt] = 2这种赋值方式必须在[ first,last ]之内,push_back会默认从last后的下个位置插入一个对象并调整last;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值