代码随想录算法训练营打卡day02-2|59 螺旋矩阵II(循环不变量)

学习来自《代码随想录》

题目建议:  本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。 

题目链接:力扣

文章讲解:代码随想录

视频讲解:一入循环深似海 | LeetCode:59.螺旋矩阵II_哔哩哔哩_bilibili

 59 螺旋矩阵II(循环不变量)

1 题目描述

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

例如输入6

输出

[

[1, 2, 3, 4, 5, 6,],

[20,21,22,23,24, 7],

[19,32,33,34,25, 8],

[18,31,36,35,26, 9],

[17,30,29,28,27,10],

[16,15,14,13,12,11]

]

输入5

输出

[

[1, 2, 3, 4, 5],

[16,17,18,19,6],

[15,24,25,20,7],

[14,23,22,21,8],

[13,14,11,10,9]

]

2 我的思路

按1-n^顺序打印,填充二维数组,但是不知道怎么代码实现

3 题解

方法一:顺时针螺旋填充二维数组

画矩阵的过程:顺时针画每条边,画一圈需要画4边

需要提前制定画的规则(循环不变量):每条边在转弯处涉及到边界值的交叉,需要按照一个规则来画,否则遗漏或者重复边界值,规则例如左闭右开、左闭右闭、左开右闭

如何实现画矩阵的过程,需要设计哪些控制参数,

1、要画的圈数loop = n/2 ,当n=偶数时,画完圈即结束打印,当n=奇数时,画完圈还有中心值要填充。nums[n/2][n/2] = 最大数即n^2

2、打印正方形二维数组,数组元素的下标是(i,j)

3、每一圈的开始位置是nums[0][0]、nums[1][1]、nums[2][2].....nums[圈数-1][圈数-1]

4、每一边遍历范围是什么?以下以左闭右开原则为例见图

 代码:
java版本:
class Solution {
    public int[][] generateMatrix(int n) {
        int i,j = 0; //用于二维数组的下标
        int loop = n/2; //计算画的圈数,控制圈数循环
        int count = 1;//用来给矩阵每个元素赋值
        int start = 0;//控制每圈开始的位置
        int offset = 1;//偏移量,每画一圈+1
        int[][] nums = new int[n][n];//存储矩阵结果的二维数组

        //每循环一次,画一圈
        while(loop-- > 0){
            //从左到右画上边,左闭右开
            for(j = start ; j < n - offset ; j++){
                nums[start][j] = count++;
            }
            //从上到下画右边,左闭右开
            for(i = start ; i < n - offset; i++){
                nums[i][j] = count++;
                }
            //从右往左画下边,左闭右开
            for(; j > start; j--){
                nums[i][j]=count++;
            }
            //从下到上画左边,左闭右开
            for(; i > start; i--){
                nums[i][j]=count++;
            }
            //画完一圈后,下一圈起始点横纵坐标+1, [0][0]、[1][1]、[2][2]...
            start++;
            //画完一圈后,每边遍历的范围n-offset要缩短
            offset++;
        }
        //如果n是奇数,需要单独非最中心的位置赋值
        if (n%2 == 1){
            nums[n/2][n/2] = count;
        }
        return nums;
    }      
}

复杂度分析:

时间复杂度O(n^2) 模拟二维数组的构建

空间复杂度O(1) 除了返回的矩阵以外,空间复杂度是常数

如果算返回的矩阵,空间复杂度为O(n^2)

python版本:

1、注意二维列表的定义方法

使用列表推导式

创建一个m*n的二维列表,并初始化元素为k:

[ [k]*n for _ in range(m)]

或者

[[k for _ in range(n)] for _ in range(m)] #两层推导式

2、还有因为range()函数是创建左闭右开的列表,for循环结束后,j或i并没有取到最后开区间的值,而这个值又是下一条边横坐标或纵坐标的固定值,所以在执行完for循环后,需要额外加一条语句。

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        count = 1
        start,i,j = 0,0,0
        offset = 1
        loop = n//2 #旋转圈数,整除
        nums = [[0] * n for _ in range(n)] #定义一个长度为n的二维数组放返回结果

        while loop > 0:
            for j in range(start, n - offset):
                nums[start][j] = count
                count += 1
            j = j + 1
            for i in range(start, n - offset):
                nums[i][j] = count
                count += 1
            i = i + 1
            for j in range(n - offset, start,-1):
                nums[i][j] = count
                count += 1
            j = j - 1
            for i in range(n -offset, start,-1 ):
                nums[i][j] = count
                count += 1
            i = i - 1
            start += 1
            offset += 1
            loop -= 1

        if n%2 == 1:
           nums[n//2][n//2] = count
        return nums

方法二:分层填充二维数组(力扣官方解答给出的另一种思路,待学习)

总结

1、思路不难代码难

画矩阵,但是如何画矩阵,需要考虑哪些变量(每圈起始值,遍历的范围),用什么控制画矩阵的循环(圈数),并且有哪些需要特殊处理的情况(n为奇数/偶数)。还有需要遵循一个规则(循环不变量原则)画下来才不会让边界值打架。

画个实例图非常重要,更容易分析出每边的范围和变量是怎么变化的。

2、改写python过程中,二维列表不会创建,边界值有点不清晰。

关联题目

  • 54.螺旋矩阵
  • 剑指Offer 29.顺时针打印矩阵
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值