首页 > 其他分享 >【代码随想录】一、数组:5.螺旋矩阵

【代码随想录】一、数组:5.螺旋矩阵

时间:2024-08-15 21:17:04浏览次数:15  
标签:count 遍历 start ++ 随想录 nums 矩阵 int 数组

本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。

1.题目1:59. 螺旋矩阵 II

1.1.解法1:模拟

本题的重点还是像之前的“704.二分查找”,坚持循环不变量原则,即在本题中遍历每条边时,坚持相同的原则

如下是一个示例,即n=5,我们考虑根据圈数和边数来进行遍历:
由外圈到内圈,而边的方向则为:①从左到右、②从上到下、③从右到左、④从下到上。
(1)从外圈到内圈:引入start变量作为“转圈”开始的位置,初始时start的值为0;第二圈时,start的值为1。
(2)边①②③④:这里在遍历每条边时,始终坚持“左闭右开”,也就是遍历①时1、2、3、4,遍历②时5、6、7、8,遍历③时9、10、11、12,遍历④时13、14、15、16。通过offset来控制每条边遍历结束的位置(n-offset),相应第二圈时,offset的值+1。
(3)当n为奇数时,中间会剩下一个数,如图中“25”,我们最后对中间数进行单独赋值。
image

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>>nums(n, vector<int>(n, 0));
        int loop = n / 2; // 要旋转的圈数
        int start = 0; // 起始位置
        int offset = 1; // 控制每一条边遍历的长度,每次循环右边界收缩一位
        int count = 1; // 用于赋值
        while (loop--) {
            int j = start, i = start;
            // 以下四个for循环即旋转了一圈
            // (1)从左向右
            for (; j < n - offset; j++) {
                nums[i][j] = count++;
            }
            // (2)从上向下
            for (; i < n - offset; i++) {
                nums[i][j] = count++;
            }
            // (3)从右向左
            for (; j > start; j--) {
                nums[i][j] = count++;
            }
            // (4)从下向上
            for (; i > start; i--) {
                nums[i][j] = count++;
            }
            start++; // 第二圈开始的时,起始位置要加1
            offset += 1; // 控制每一圈里每一条边遍历的长度
        }
        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2 == 1) nums[n / 2][n / 2] = count;
        return nums;
    }
};

● 时间复杂度:\(O(n^2)\)。
● 空间复杂度:\(O(1)\)。

2.题目2:54.螺旋矩阵

类似于59.螺旋矩阵II,但本题矩阵行列不一定相等,且要求顺时针方向输出指定的矩阵。

2.1.解法1:模拟

思路上和59.螺旋矩阵II相似,都是:由外圈到内圈,而边的方向则为:①从左到右、②从上到下、③从右到左、④从下到上。
不过需要注意一点,因为行数列数不相等的情况下:
1.旋转的圈数应为:min(列数,行数) / 2。
2.当min(列数,行数)为奇数时:
min(列数,行数) = 列数,即还剩余一个中间列没有被遍历到;
min(列数,行数) = 行数,即还剩余一个中间行没有被遍历到;
剩余的中间行或是中间列还需要单独去进行遍历,按照题意填充到目标数组中。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        vector<int>nums(m * n);
        int start = 0;
        int loop = min(m, n) / 2;
        int count = 0;
        int offset = 1;
        int i, j;
        while (loop --) {
            i = start, j = start;
            // (1)从左往右
            for (; j < n - offset; j++) {
                nums[count++] = matrix[i][j];
            }
            // (2)从上往下
            for (; i < m - offset; i++) {
                nums[count++] = matrix[i][j];
            }
            // (3)从右往左
            for (; j > start; j--) {
                nums[count++] = matrix[i][j];
            }
            // (4)从下往上
            for (; i > start; i--) {
                nums[count++] = matrix[i][j];
            }
            start++;
            offset++;
        }

        int mid = min(m, n) / 2;
        if (min(m, n) % 2) {
            if (m > n) { // 剩下一个中间列
                for (int i = mid; i < mid + m - n + 1; i++) {
                    nums[count++] = matrix[i][mid];
                }
            }
            else { // 剩下一个中间行
                for (int i = mid; i < mid + n - m + 1; i++) {
                    nums[count++] = matrix[mid][i];
                }                
            }
        }
        return nums;
    }
};

● 时间复杂度:\(O(n^2)\) 模拟遍历二维矩阵的时间。
● 空间复杂度:\(O(1)\)。

2.2.解法2:模拟(简洁)

这是力扣上某大佬的一种解法
1.设定上下左右边界。
2.从左向右,第一行已经遍历完,便可以从中删除,相当于重新定义上边界。
3.如果重新定义的上边界与下边界交错,表示遍历结束,跳出循环,返回答案。
若不交错,继续向下、向左、向上遍历,操作步骤同1.2。
4.循环以上步骤,直至两边界交错,跳出循环,返回答案。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int>ans;
        if (matrix.empty()) return ans;
        int left = 0, right = matrix[0].size() - 1, top = 0, bottom = matrix.size() - 1;
        while (true) {
            // 1.从左向右
            for (int i = left; i <= right; i++) {
                ans.push_back(matrix[top][i]);
            }
            if (++top > bottom) break;
            // 2.从上向下
            for (int i = top; i <= bottom; i++) {
                ans.push_back(matrix[i][right]);
            }
            if (--right < left) break;
            // 3.从右向左
            for (int i = right; i >= left; i--) {
                ans.push_back(matrix[bottom][i]);
            }
            if (--bottom < top) break;
            // 4.从下向上
            for (int i = bottom; i >= top; i--) {
                ans.push_back(matrix[i][left]);
            }
            if (++left > right) break;
        }
        return ans;
    }
};

3.题目3:LCR 146. 螺旋遍历二维数组

这题的解法同54。

3.1.解法1:模拟

class Solution {
public:
    vector<int> spiralArray(vector<vector<int>>& array) {
        if (array.size() == 0 || array[0].size() == 0) return {};
        int m = array.size(), n = array[0].size();
        vector<int>nums(m * n);
        int loop = min(m, n) / 2;
        int start = 0;
        int offset = 1;
        int count = 0;
        int i, j;
        while (loop --) {
            i = start, j = start;
            for (; j < n - offset; j++) {
                nums[count++] = array[i][j];
            }
            for (; i < m - offset; i++) {
                nums[count++] = array[i][j];
            }
            for (; j > start; j--) {
                nums[count++] = array[i][j];
            }
            for (; i > start; i--) {
                nums[count++] = array[i][j];
            }
            start++;
            offset++;            
        }

        int mid = min(m, n) / 2;
        if (min(m, n) % 2) {
            if (m > n) {
                for (int i = mid; i < mid + m - n + 1; i++) {
                    nums[count++] = array[i][mid];
                }
            }
            else {
                for (int i = mid; i < mid + n - m + 1; i++) {
                    nums[count++] = array[mid][i];
                }
            }
        }
        return nums;
    }
};

● 时间复杂度:\(O(n^2)\) 模拟遍历二维矩阵的时间。
● 空间复杂度:\(O(1)\)。

标签:count,遍历,start,++,随想录,nums,矩阵,int,数组
From: https://www.cnblogs.com/Henfiu/p/18359109

相关文章

  • KMP算法——理解 next 数组
    !注意!本文与《王道》,《严书》有所不同,字符串均从第0位开始,next数组没有添加常数1。博客为梳理思路所用,难免纰漏,希望不吝赐教。在字符串匹配中,设m为待匹配的主串S长度,n为找寻的模式串T长度。如:在主串S='ababc'中寻找模式串T='abc'则字符串匹配算法返回S中第......
  • 代码随想录算法训练营 | 动态规划 part01
    509.斐波那契数509.斐波那契数状态转移方程:F(0)=0,F(1)=1F(n)=F(n-1)+F(n-2),其中n>1递归,太多重复计算classSolution{public:intfib(intn){if(n==0||n==1){returnn;}returnfib(n-1)......
  • JS 数组的用法
    一、常用的测试写法//array的写法varmyArray=["Apple","Orange","Banana"];//一、正常循环写法如下:varfruitFinal3=""for(vari=0;i<myArray.length;i++){fruitFinal3+=myArray[i]+""......
  • 代码随想录算法训练营第一天 | 704. 二分查找,27. 移除元素
     704.二分查找题目链接:https://leetcode.cn/problems/binary-search/1,左闭右闭publicintsearch(int[]nums,inttarget){intlow=0;inthigh=nums.length-1;while(low<=high){intmid=(high+low)/2;if(num......
  • JS 对象与数组互相嵌套的复杂例子
    JS写法如下:constmyObj={name:"John",age:30,cars:[{name:"Ford",models:["Fiesta","Focus","Mustang"]},{name:"BMW",models:["32......
  • JavaScript实现数组与树结构的相互转换
    1、将树结构数据转换为数组(按照树结构自上而下的顺序转换)树结构:树结构数据样例:代码转换://将树结构数据转换为数组treeNodes为树结构形式的数据functiontreeToArray(treeNodes){letresult=[];//递归函数traverse,用于处理单个节点functiontraverse(node......
  • 【OpenCV教程】OpenCV中对矩阵的常用操作
    @目录1.全零矩阵2.全一矩阵3.单位矩阵4.矩阵转置5.求逆矩阵6.逗号式分隔创建矩阵7.矩阵定义(只列出常用的)7.1数据类型Scalar8.通过ptr与at函数遍历矩阵8.1Vec类型9.通过迭代器遍历矩阵(easybutveryveryslow)1.全零矩阵CV_NODISCARD_STDstaticMatExprMat::zeros(intr......
  • 代码随想录算法训练营第43天:动态规划part10:子序列问题
    300.最长递增子序列力扣题目链接(opensnewwindow)给你一个整数数组nums,找到其中最长严格递增子序列的长度。子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7]是数组[0,3,1,6,2,2,7]的子序列。示例1:输入:nums=[10,9,2......
  • 代码随想录day30 || 452 引爆气球,435 无重叠区间,763 划分字母区间
    452射爆气球funcfindMinArrowShots(points[][]int)int{ //思路,尝试按照startasc,endasc排序一下,取交集射爆 iflen(points)==1{ return1 } sort.Slice(points,func(i,jint)bool{ ifpoints[i][0]==points[j][0]{ returnpoints[i][1]<points......
  • Springmvc -- 使用`@RequestParam`接收数组类型参数
    在SpringMVC中,处理数组类型的请求参数是一个常见需求,尤其是在处理表单数据或查询参数时。SpringMVC提供了多种方式来接收数组类型的请求参数,包括使用@RequestParam注解、直接绑定到方法参数、以及使用@ModelAttribute注解。本文将深入探讨这些方式的用法、优缺点以及如何......