栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

LeetCode 54.螺旋矩阵 - 原地修改

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

LeetCode 54.螺旋矩阵 - 原地修改

【LetMeFly】54.螺旋矩阵 - 原地修改

力扣题目链接:https://leetcode.cn/problems/spiral-matrix/

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

示例 1:

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

示例 2:

输入:matrix = [[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 = = m a t r i x . l e n g t h m == matrix.length m==matrix.length
  • n = = m a t r i x [ i ] . l e n g t h n == matrix[i].length n==matrix[i].length
  • 1 < = m , n < = 10 1 <= m, n <= 10 1<=m,n<=10
  • − 100 ≤ m a t r i x [ i ] [ j ] ≤ 100 -100 leq matrix[i][j] leq 100 −100≤matrix[i][j]≤100
思路

我们只需要从 ( 0 , 0 ) (0, 0) (0,0)开始,按题目意思模拟即可。

方法一:模拟(简单,但需要修改原数组)

先小开心一波,这次执行效率小高了一次嘻嘻

我们定义一个directions数组,来代表要遍历的方向。

const int directions[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};  // 分别对应:

然后还需要一个变量nowDirection,来记录当前的方向。

用变量loc来记录当前已经遍历过的元素的数量,当已遍历的数量小于总元素个数时,继续遍历。

int loc = 0;  // 遍历了几个元素了
while (loc < n) {
    继续遍历
}

每次遍历时,先把当前位置的元素存入答案中(用 x x x和 y y y记录当前位置,初始值都为 0 0 0),标记当前位置为已遍历过并把 l o c + 1 loc + 1 loc+1。

因为题目中说元素的数据范围是 [ − 100 , 100 ] [-100,100] [−100,100],所以我们可以把已遍历过的元素标记为 101 101 101

ans[loc++] = matrix[x][y];
matrix[x][y] = ALREADY;  // ALREADY的值可以是101

然后就看下一个位置是否未被遍历过

#define ifOK(x, y) if (x >= 0 && x < matrix.size() && y >= 0 && y < matrix[0].size() && matrix[x][y] != ALREADY)  // 判断(x, y)是否OK(既在数据范围内又没被遍历过)
int nx = x + directions[nowDirection][0];
int ny = y + directions[nowDirection][1];
ifOK(nx, ny) {
    ...
}

如果下一个元素可行就更新 x x x和 y y y为当前方向的下一个元素;

如果下一个元素不可行就更改遍历方向为下一个方向,并更新 x x x和 y y y为新方向的下一个元素。

nowDirection = (nowDirection + 1) % 4;
x += directions[nowDirection][0];
y += directions[nowDirection][1];
  • 时间复杂度 O ( n m ) O(nm) O(nm)
  • 空间复杂度 O ( 1 ) O(1) O(1),但是注意如果不允许修改原数组,则此方法将要消耗O(nm)的空间复杂度。
AC代码 C++
#define ALREADY 101
#define ifOK(x, y) if (x >= 0 && x < matrix.size() && y >= 0 && y < matrix[0].size() && matrix[x][y] != ALREADY)
const int directions[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};  // 

class Solution {
public:
    vector spiralOrder(vector>& matrix) {
        int n = matrix.size() * matrix[0].size();
        vector ans(n);
        int nowDirection = 0;  // 现在的方向
        int loc = 0;  // 遍历了几个元素了
        int x = 0, y = 0;  // 当前应该遍历的位置
        while (loc < n) {
            ans[loc++] = matrix[x][y];
            matrix[x][y] = ALREADY;
            int nx = x + directions[nowDirection][0];
            int ny = y + directions[nowDirection][1];
            ifOK(nx, ny) {
                x = nx, y = ny;
            }
            else {
                nowDirection = (nowDirection + 1) % 4;
                x += directions[nowDirection][0];
                y += directions[nowDirection][1];
            }
        }
        return ans;
    }
};
方法二:模拟(不那么好想,但不需要修改原数组)

方法一中,我们判断前进方向是否修改的方式是“看下一个点有没有走过”。因此我们把已经走过的点做了个标记。

那么,有没有什么 不看下一个点是否走过就能判断是否该转向了 的办法呢?答案当然是有的。

接下来让我们来绘制一下走向图:

以5*6的表格为例,生成HTML表格的Emmet代码为(在支持Emmet语法的编辑器中输入下面代码按回车即可):

center>table[]>tr[]*5>td[]*6

然后填入要前进的方向:

⤵️
⮫⤵️
⮫⤵️
↖↲
↖↲

图片版本为:

不难发现,若以下标为 0 0 0开始:

  • 需要右转下的位置都在一条负对角线上,且这些点满足 x + y = 列 数 − 1 x+y=列数 - 1 x+y=列数−1。因此,当前进方向为向右且遍历到的位置坐标满足 x + y = 列 数 − 1 x+y=列数 - 1 x+y=列数−1时,应当调整遍历方向为向下。
  • 同理,下转左的条件为 x − y = 行 数 − 列 数 x-y=行数-列数 x−y=行数−列数
  • 左转上的条件为 x + y = 行 数 − 1 x+y=行数-1 x+y=行数−1
  • 上转右的条件为 x − y = 1 x-y=1 x−y=1

这样我们就不修改原始数组,就能判断什么时候该改变方向了。

  • 时间复杂度 O ( n m ) O(nm) O(nm)
  • 空间复杂度 O ( 1 ) O(1) O(1),因为根本不需要修改原数组
AC代码 C++
const int directions[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};  // 

class Solution {
public:
    vector spiralOrder(vector>& matrix) {
        int rows = matrix.size(), cols = matrix[0].size();  // 行数,列数
        vector ans(rows * cols);
        int nowDirection = 0;
        int loc = 0;
        int x = 0, y = 0;
        while (loc < rows * cols) {
            ans[loc++] = matrix[x][y];
            if (nowDirection == 0 && x + y == cols - 1) {  // 右转下
                nowDirection = 1;
            }
            else if (nowDirection == 1 && x - y == rows - cols) {  // 下转左
                nowDirection = 2;
            }
            else if (nowDirection == 2 && x + y == rows - 1) {  // 左转上
                nowDirection = 3;
            }
            else if (nowDirection == 3 && x - y == 1) {  // 上转右
                nowDirection = 0;
            }
            x += directions[nowDirection][0];
            y += directions[nowDirection][1];
            // // DebugBegin
            // printf("x = %d, y = %d, nowDirection = %dn", x, y, nowDirection);
            // if (!(x >= 0 && x < rows && y >= 0 && y < cols)) {
            //     printf("Error!n");
            //     break;
            // }
            // // DebugEnd
        }
        return ans;
    }
};

这是我较为用心写的一篇博客,题解图片是由HTML画的。同步发文于CSDN,原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/125016209

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/935486.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号