【LeetCode题目详解】59. 螺旋矩阵 II 54. 螺旋矩阵 LCR 146. 螺旋遍历二维数组(c++)

news2024/9/28 19:41:08

这篇文章的题目稍微难一点

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

一、59. 螺旋矩阵 II

题目:

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

示例 1:

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

示例 2:

输入:n = 1
输出:[[1]]

提示:

  • 1 <= n <= 20

思路

这道题目可以说在面试中出现频率较高的题目,本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。

要如何画出这个螺旋排列的正方形矩阵呢?

相信很多同学刚开始做这种题目的时候,上来就是一波判断猛如虎。

结果运行的时候各种问题,然后开始各种修修补补,最后发现改了这里那里有问题,改了那里这里又跑不起来了。

大家还记得我们在这篇文章数组:每次遇到二分法,都是一看就会,一写就废

(opens new window)中讲解了二分法,提到如果要写出正确的二分法一定要坚持循环不变量原则

而求解本题依然是要坚持循环不变量原则。

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去。

可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是一进循环深似海,从此offer是路人

这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。

那么我按照左闭右开的原则,来画一圈,大家看一下:

这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。

这也是坚持了每条边左闭右开的原则。

一些同学做这道题目之所以一直写不好,代码越写越乱。

就是因为在画每一条边的时候,一会左开右闭,一会左闭右闭,一会又来左闭右开,岂能不乱。

代码如下,已经详细注释了每一步的目的,可以看出while循环里判断的情况是很多的,代码里处理的原则也是统一的左闭右开。

整体C++代码如下:

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
        int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
        int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
        int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int count = 1; // 用来给矩阵中每一个空格赋值
        int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int i,j;
        while (loop --) {
            i = startx;
            j = starty;

            // 下面开始的四个for就是模拟转了一圈
            // 模拟填充上行从左到右(左闭右开)
            for (j = starty; j < n - offset; j++) {
                res[startx][j] = count++;
            }
            // 模拟填充右列从上到下(左闭右开)
            for (i = startx; i < n - offset; i++) {
                res[i][j] = count++;
            }
            // 模拟填充下行从右到左(左闭右开)
            for (; j > starty; j--) {
                res[i][j] = count++;
            }
            // 模拟填充左列从下到上(左闭右开)
            for (; i > startx; i--) {
                res[i][j] = count++;
            }

            // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            startx++;
            starty++;

            // offset 控制每一圈里每一条边遍历的长度
            offset += 1;
        }

        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2) {
            res[mid][mid] = count;
        }
        return res;
    }
};
  • 时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
  • 空间复杂度 O(1)
  • 类似题目

  • 54.螺旋矩阵
  • (opens new window)
  • 剑指Offer 29.顺时针打印矩阵
  • (opens new window)

二、54. 螺旋矩阵

题目:

给你一个 mn 列的矩阵 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 == matrix.length
  • n == matrix[i].length
  • 1 <= m, n <= 10
  • -100 <= matrix[i][j] <= 100

题解:

两种题解:一种是根据上面那一题的思路去改的,稍微复杂一点

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if (matrix.size() == 0 || matrix[0].size() == 0) {
            return {};
        }
        vector<int> res;
        int i, j;
        int m = matrix.size(), n = matrix[0].size();
        int startx = 0, starty = 0;
        int offset = 1;

        // 特判:只有一行
        if (m == 1) {
            return matrix[0];
        }
        // 特判:只有一列
        if (n == 1) {
            for (i = 0; i < m; i++) {
                res.push_back(matrix[i][0]);
            }
            return res;
        }

        while (startx <= n - offset && starty <= m - offset) {
            i = startx;
            j = starty;

            for (j = starty; j < n - offset && res.size() < m * n; j++) {
                res.push_back(matrix[i][j]);
            }
            for (i = startx; i < m - offset && res.size() < m * n; i++) {
                res.push_back(matrix[i][j]);
            }
            for (; j > starty && res.size() < m * n; j--) {
                res.push_back(matrix[i][j]);
            }
            for (; i > startx && res.size() < m * n; i--) {
                res.push_back(matrix[i][j]);
            }

            startx++;
            starty++;

            offset += 1;
        }

        if (res.size() < m * n) {
            if (n % 2 && m % 2) {
                res.push_back(matrix[i][j]);
            } else if (n % 2) {
                for (; i >= startx && res.size() < m * n; i--) {
                    res.push_back(matrix[i][j]);
                }
            } else if (m % 2) {
                for (; j >= starty && res.size() < m * n; j--) {
                    res.push_back(matrix[i][j]);
                }
            }
        }

        return res;
    }
};

第二种是力扣上的题解,比较简洁一点

可以将矩阵看成若干层,首先输出最外层的元素,其次输出次外层的元素,直到输出最内层的元素。

定义矩阵的第 kkk 层是到最近边界距离为 kkk 的所有顶点。例如,下图矩阵最外层元素都是第 111 层,次外层元素都是第 222 层,剩下的元素都是第 333 层。

[[1, 1, 1, 1, 1, 1, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 2, 3, 3, 3, 2, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 1, 1, 1, 1, 1, 1]]

对于每层,从左上方开始以顺时针的顺序遍历所有元素。假设当前层的左上角位于 (top,left)(\textit{top}, \textit{left})(top,left),右下角位于 (bottom,right)(\textit{bottom}, \textit{right})(bottom,right),按照如下顺序遍历当前层的元素。

    从左到右遍历上侧元素,依次为 (top,left)(\textit{top}, \textit{left})(top,left) 到 (top,right)(\textit{top}, \textit{right})(top,right)。

    从上到下遍历右侧元素,依次为 (top+1,right)(\textit{top} + 1, \textit{right})(top+1,right) 到 (bottom,right)(\textit{bottom}, \textit{right})(bottom,right)。

    如果 left<right\textit{left} < \textit{right}left<right 且 top<bottom\textit{top} < \textit{bottom}top<bottom,则从右到左遍历下侧元素,依次为 (bottom,right−1)(\textit{bottom}, \textit{right} - 1)(bottom,right−1) 到 (bottom,left+1)(\textit{bottom}, \textit{left} + 1)(bottom,left+1),以及从下到上遍历左侧元素,依次为 (bottom,left)(\textit{bottom}, \textit{left})(bottom,left) 到 (top+1,left)(\textit{top} + 1, \textit{left})(top+1,left)。

遍历完当前层的元素之后,将 left\textit{left}left 和 top\textit{top}top 分别增加 111,将 right\textit{right}right 和 bottom\textit{bottom}bottom 分别减少 111,进入下一层继续遍历,直到遍历完所有元素为止。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if (matrix.size() == 0 || matrix[0].size() == 0) {
            return {};
        }

        int rows = matrix.size(), columns = matrix[0].size();
        vector<int> order;
        int left = 0, right = columns - 1, top = 0, bottom = rows - 1;
        while (left <= right && top <= bottom) {
            for (int column = left; column <= right; column++) {
                order.push_back(matrix[top][column]);
            }
            for (int row = top + 1; row <= bottom; row++) {
                order.push_back(matrix[row][right]);
            }
            if (left < right && top < bottom) {
                for (int column = right - 1; column > left; column--) {
                    order.push_back(matrix[bottom][column]);
                }
                for (int row = bottom; row > top; row--) {
                    order.push_back(matrix[row][left]);
                }
            }
            left++;
            right--;
            top++;
            bottom--;
        }
        return order;
    }
};

复杂度分析

    时间复杂度:O(mn)O(mn)O(mn),其中 mmm 和 nnn 分别是输入矩阵的行数和列数。矩阵中的每个元素都要被访问一次。

    空间复杂度:O(1)O(1)O(1)。除了输出数组以外,空间复杂度是常数。

三、LCR 146. 螺旋遍历二维数组

题目:

给定一个二维数组 array,请返回「螺旋遍历」该数组的结果。

螺旋遍历:从左上角开始,按照 向右向下向左向上 的顺序 依次 提取元素,然后再进入内部一层重复相同的步骤,直到提取完所有元素。

示例 1:

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

示例 2:

输入:array  = [[1,2,3,4],[12,13,14,5],[11,16,15,6],[10,9,8,7]]
输出:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]

限制:

  • 0 <= array.length <= 100
  • 0 <= array[i].length <= 100

注意:本题与主站 54 题相同:. - 力扣(LeetCode)

题解:

这一题基本和上面那一题一样

class Solution {
    public int[] spiralArray(int[][] array) {
        if (array == null || array.length == 0 || array[0].length == 0) {
            return new int[0];
        }
        int rows = array.length, columns = array[0].length;
        int[] order = new int[rows * columns];
        int index = 0;
        int left = 0, right = columns - 1, top = 0, bottom = rows - 1;
        while (left <= right && top <= bottom) {
            for (int column = left; column <= right; column++) {
                order[index++] = array[top][column];
            }
            for (int row = top + 1; row <= bottom; row++) {
                order[index++] = array[row][right];
            }
            if (left < right && top < bottom) {
                for (int column = right - 1; column > left; column--) {
                    order[index++] = array[bottom][column];
                }
                for (int row = bottom; row > top; row--) {
                    order[index++] = array[row][left];
                }
            }
            left++;
            right--;
            top++;
            bottom--;
        }
        return order;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1386569.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

原生IP代理如何帮助跨境电商店铺做谷歌广告投放业务的?

随着全球化的发展&#xff0c;越来越多的电商店铺开始拓展跨境业务&#xff0c;而谷歌广告作为全球最大的广告平台之一&#xff0c;为跨境电商店铺带来了巨大的收益和商机。 然而&#xff0c;由于谷歌广告的地域限制和审查机制&#xff0c;店铺很难直接进行投放业务&#xff0…

gradle版本中-bin与-all区别

打开android studio下载的gradle文件&#xff0c;发现-all比-bin多了一个docs文件夹和一个src文件夹。-bin是编译后的二进制发布版&#xff0c;-all还包含了源码和文档&#xff0c;比-bin大了几十兆&#xff0c;两者其余没有区别。 android开发只关注gradle功能不关注实现的情况…

Mingw32编译opencv库

文章目录 1. 准备工作2. 编译cmake构建程序mingw32-make编译 3. 安装4. 安装完的结果 注意&#xff1a; mingw32-make编译的库和MSVC编译的库不兼容&#xff0c;MSVC和mingw-make生成的动态库使用的是不同的ABI&#xff08;Application Binary Interface&#xff09;&#xff0…

如何实现无公网ip固定TCP端口地址远程连接Oracle数据库

文章目录 前言1. 数据库搭建2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射 3. 公网远程访问4. 配置固定TCP端口地址4.1 保留一个固定的公网TCP端口地址4.2 配置固定公网TCP端口地址4.3 测试使用固定TCP端口地址远程Oracle 前言 Oracle&#xff0c;是甲骨文公司的一款关系…

64位ATT汇编语言学习第一课:汇编和链接

源文件exitTest.s内容如下&#xff1a; # This is the first program .global _start .section .text _start:movq $60,%raxmovq $9,%rdisyscall源文件里边放的就是源代码&#xff0c;而我这里源代码是使用汇编语言写的&#xff0c;都是一些人类都可以阅读的字符。之后需要经过…

【UE Niagara】网格体渲染器初识

目录 效果 步骤 一、创建网格体粒子 二、设置粒子生成速率 三、设置粒子初始大小 四、设置粒子生成的初始位置 五、设置粒子移动速度 六、设置粒子旋转 七、 设置粒子大小变化 效果 步骤 一、创建网格体粒子 新建一个Niagara粒子系统 选择“Simple Sprite Burs…

Ubuntu配置NFS客户端和服务端详解——手把手配置

Ubuntu配置NFS客户端和服务端 如果您想实现远程访问并修改 ROS 主机中 Ubuntu 上的文件&#xff0c;可以通过 NFS挂载的方式。虚拟机上的 Ubuntu 系统可以通过 NFS 的方式来访问 ROS 主机中Ubuntu 系统的文件&#xff0c;NFS 分为服务器挂载和客户端访问。这里虚拟机上的 Ubun…

小型洗衣机怎么用?好用不贵的小型洗衣机推荐

近期&#xff0c;有不少小伙伴都在议论“对于内衣是机洗好&#xff0c;还是手洗”这个问题&#xff0c;对于机洗党认为家用的洗衣机就能清洁干净内衣物&#xff0c;而坚定的手洗党则是认为应该用手去洗&#xff0c;因为机洗的话&#xff0c;其他大件衣服混在一起洗&#xff0c;…

Picturesocial | 开发实践:如何在15分钟内将应用容器化

在常见的软件架构体系中&#xff0c;容器无疑是一个技术热点。有些开发者在工作中熟练使用容器技术&#xff0c;有些可能刚刚开始容器之旅。 面对容器使用经验不同的各类开发者&#xff0c;我们希望通过这个系列文章&#xff0c;由浅入深地介绍如何使用容器技术来构建&#xf…

小白从事光伏行业:如何快速入行?

鹧鸪云 在政策引导和产业链不断优化的背景下&#xff0c;国内光伏市场不断扩大&#xff0c;国际市场中也崭露头角&#xff0c;许多人纷纷进入光伏行业&#xff0c;但是苦于不知如何入手。本文着重于为刚刚进入光伏行业的新手小白介绍进入光伏行业的好办法。 光伏行业利用太阳…

【深度学习I-基础知识】

深度学习I-基础知识 1 基础知识1.1 模型的基本概念1.2 机器学习1.2.1 概率建模1.2.2 核方法1.2.3 决策树、随机森林和梯度提升机 1.3 深度学习1.3.1 张量1.3.2 数据批量1.3.3 张量运算1.3.4 训练过程 1 基础知识 1.1 模型的基本概念 模型是现实世界中一类具有泛化共性的真实系…

2024 外网数字化考试——精准限制只允许访问考试站点

一、适用场景&#xff1a; 1、防止考试作弊。校园内&#xff0c;需要用到外网的某个考试站点时&#xff0c;只允许浏览器访问考试网站&#xff0c;别的网站不允许访问时&#xff08;避免使用搜索引擎搜索参考或答案&#xff09;。 2、网络流量给教学资源&#xff0c;杜绝网络娱…

企业级做项目的流程

目录标题 前言企业做项目的流程 ⭐⭐总结 前言 我们平时在学校里做项目或者大作业的时候&#xff0c;基本上都是个人开发的&#xff0c;即使有小组一起开发&#xff0c;一般也不会遵守开发规范。最近入职一家企业开始实习&#xff0c;才发现开发规范竟然如此重要&#xff0c;因…

【数据结构】排序之归并排序与计数排序

个人主页 &#xff1a; zxctsclrjjjcph 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 目录 1. 前言2. 归并排序2.1 递归实现2.1.1 分析2.1.2 代码实现 2.2 非递归实现2.2.1 分析2.2.2 代码实现 3. 计数排序3.1 分析3.2 代码实现 4. 附代码4.1 Sort.h4.2 Sort.c4.3…

2. 示例:Spring Boot 入门

1.1 概述 Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。习惯优于配置 1.2 为什么使用Spring Boot J2EE笨重的开发、繁多的配置、低下的开发效率、复杂的部署流程、第三方技术集成难度大。 1.3 Spring Bo…

【python】进阶--->MySQL数据库(四)

一、主键约束 primary key : 唯一标识数据库中的每一条记录. 被主键的值唯一 主键列不能为null 每个表应该都要设置主键添加主键约束 在创建表时,直接在字段后面添加主键约束 create table 表名 (字段名 类型(长度) primary key )创建表时,不直接在字段后面添加主键…

二、Spring Boot与Mybatis代码自动生成

一、Mybatis代码自动生成 下载自动生成java包&#xff1a;https://www.alipan.com/s/7sGR9uGKoVh 下面就是根据这个进行简单配置即可 1.修改 下面主要修改这个文件 如下 如下 如下 运行 2.结果 解释&#xff1a;在运行之后&#xff0c;就会在上面输入的包里面创建…

【ubuntu】docker中如何ping其他ip或外网

docker中如何ping其他ip或外网 示例图&#xff1a; 运行下面命令&#xff1a; docker run -it --namehei busybox看情况需要加权限 sudo&#xff0c;即&#xff1a; sudo docker run -it --namehei busyboxping 外网 ping -c 4 www.baidu.comping 内网 ping -c 4 192.168.…

rime中州韵小狼毫 联想词组 滤镜

教程目录&#xff1a;rime中州韵小狼毫须鼠管安装配置教程 保姆级教程 100增强功能配置教程 在 rime中州韵小狼毫 自定义词典 一文中&#xff0c;我们分享了如何在rime中州韵小狼毫须鼠管输入法中定义用户自定义词典&#xff1b;通过自定义词典&#xff0c;我们可以很方便的在…

LeetCode:82. 删除排序链表中的重复元素 II(C++、Java)

目录 82. 删除排序链表中的重复元素 II 题目描述&#xff1a; 实现代码与解析&#xff1a; 链表遍历&#xff1a; 实现代码与解析&#xff1a; 82. 删除排序链表中的重复元素 II 题目描述&#xff1a; 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复…