leetcode 力扣刷题 旋转矩阵(循环过程边界控制)

news2024/11/24 14:58:34

力扣刷题 旋转矩阵

  • 二维矩阵按圈遍历(顺时针 or 逆时针)遍历
  • 59. 旋转矩阵Ⅱ
  • 54. 旋转矩阵
  • 剑指 Offer 29. 顺时针打印矩阵

二维矩阵按圈遍历(顺时针 or 逆时针)遍历

下面的题目的主要考察点都是,二维数组从左上角开始顺时针(或者逆时针)按圈遍历数组的过程。顺时针按圈遍历的过程如下:
在这里插入图片描述
对于每一圈,分为四条边,循环遍历就好。这时,对于四个角的元素的处理,可以将四条边的遍历分为以下两种情况:
在这里插入图片描述

  • 第一种:每条边都从对应一角开始,遍历对应边的时候,最后一个元素留给下一条边;比如第一条绿色的边,最后一个元素就没有遍历;第二条黄色的变就从左上角元素开始,相应的最左下角的元素没有访问;以此类推;
    代码实现(C++):
        //count表示访问了的元素个数,控制遍历完数组没有
        while(count <= n*n){
        	//i,j是行、列的下标,每次总是从[0,0],[1,1]开始一圈循环
            int i = p;
            int j = p;
            //每圈最上面一条边的遍历         
            while(j < n - 1 - p){
            //因为最一个元素[i][n-1-p]留给下一条边,因此这里不取等
                ans[i][j++] = count++;
            }
            //每圈最右边的一条边的遍历
            while(i < n - 1 - p){
            //因为最一个元素[n-1-p][j]留给下一条边,因此这里不取等
                ans[i++][j] = count++;
            }
            //每圈最下面一条边的遍历
            while(j > p){
            //因为最后一个元素[i][p]留给下一条边,因此这里不取等
                ans[i][j--] = count++;
            }
            //每圈最左边的一条边的遍历
            while(i > p){
            //因为[p][p]就是这一圈的起始点,在第一条边就遍历过了,所以这里取等
                ans[i--][j] = count++;
            }
            p++;
        }
  • 第二种:遍历每一条边是,就将该边所有未被访问的元素全部遍历;比如第一条绿色的,最后一个元素就访问了;然后第二条边黄色的就对应列的第二个开始,因为第一个已经被访问了;之后的边以此类推;
    代码实现(C++):
        //count控制遍历完了没有
        while(count <= n*n){   
        	//遍历最上边的一条边        
            for(int i = left; i <= right ; i++){
                ans[top][i] = count++;
            }
            //遍历完后top++
            top++;
            //遍历最右边的边
            for(int i = top; i <= bottom; i++){
                ans[i][right] = count++;
            }
            //遍历完后right--
            right--;
            //遍历最下边的边
            for(int i = right; i >= left ;i--){
                ans[bottom][i] = count++;
            }
            //遍历完后bottom--
            bottom--;
            //遍历最左边一条边
            for(int i = bottom; i >= top; i--){
                ans[i][left] = count++;
            }
            //遍历完后left++
            left++;
        }

59. 旋转矩阵Ⅱ

螺旋矩阵 II
题目内容如下:
在这里插入图片描述
注意点是n*n的正方形矩阵,行列数量相同。只要按照前面提到的顺时针访问数组的过程中,给每个位置递增赋值就好。俺圈遍历的过程中,需要循环遍历多少次呢?答案是(n+1)/2次。
在这里插入图片描述
但是按照上面提到的第一种俺圈遍历的过程中:

  • n为偶数时,每次减少2行,2 列,最后刚好遍历完;
  • n为奇数时,最后一次只有单独一个,因为每一行的最后一个元素都留给下一行了,所以实际上没有哪一行去遍历了。比如n=5,p=2时,i=2,j=2,n-1-p=2,由于i=j=p=n-1-p,第一种代码提到的四种循环条件都不满足。所以在最后要单独给这个位置赋值。代码如下(C++):
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        int count = 1;
        int i, j, p;
        vector<vector<int>> ans(n,vector<int>(n));
        //因为n为奇数的最后一圈在最后单独赋值,所以这里p<n/2就好
        for(int p = 0; p < n/2; p++){
            i = p;
            j = p;         
            while(j < n - 1 - p){
                ans[i][j++] = count++;
            }
            while(i < n - 1 - p){
                ans[i++][j] = count++;
            }
            while(j > p){
                ans[i][j--] = count++;
            }
            while(i > p){
                ans[i--][j] = count++;
            }
        }
        //n为奇数时,最后一个位置(最中间)单独赋值
        if( n%2 != 0){
            ans[n/2][n/2] = count;
        }
        return ans;
    }
}; 

对于第二种按圈遍历的过程,因为用top//bottom//left//right来控制,最后中间位置的能够遍历到,必须要额外的处理,代码如下(C++):

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {        
        vector<vector<int>> ans(n,vector<int>(n));
        int left = 0, right = n - 1;
        int top = 0, bottom = n -1;
        int count = 1;
        while(count <= n*n){
            int i;
            for(i = left; i <= right ; i++){
                ans[top][i] = count++;
            }
            top++;
            for(i = top; i <= bottom; i++){
                ans[i][right] = count++;
            }
            right--;
            for(i = right; i >= left ;i--){
                ans[bottom][i] = count++;
            }
            bottom--;
            for(i = bottom; i >= top; i--){
                ans[i][left] = count++;
            }
            left++;
        }
        return ans;
    }
}; 

54. 旋转矩阵

54. 旋转矩阵
题意如下:在这里插入图片描述
跟上一题不同的点在于,矩阵由nn变成了mn,m和n不一定相等,即现在的矩阵可能不再是正方形的了。那么根据m(行数)///n(偶数)是奇数还是偶数?大小关系可以分为以下七种情况:
在这里插入图片描述
分析这7种情况,得出结论,只要满足如下两种情况之一,最后就有需要单独处理的:

  • m<n并且m是奇数(不管n是奇是偶),最终会多出来一行(因为m行数更小,行先结束圈的遍历,但是列还有更多的,所以多出来一行);
  • n<m并且n是奇数(不管m是奇是偶),最终会多出来一列(因为n列数更小,列先结束圈的遍历,但是行还有很多,所以多出来一列);
    (m=n同为奇数的情况可以归为上述任意一种)。
    代码实现的过程,就是最终会判断一下是否出现上面的情况,然后单独处理这一行///这一列就好,代码如下:
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        int step_i = 0, step_j = 0, index = 0;
        int m = matrix.size(), n = matrix[0].size();
        vector<int> ans(m*n);
        //与上一题代码基本一致,只是<m/2和<n/2需要单独判断
        while(step_i < m/2 && step_j < n/2){
            int i = step_i;
            int j = step_j;
            for(; j < n - 1 -step_j; j++){
                ans[index++] = matrix[i][j];
            }
            for(; i < m - 1 - step_i; i++){
                ans[index++] = matrix[i][j];
            }
            for(; j > step_j; j--){
                ans[index++] = matrix[i][j];
            }
            for(; i > step_i ;i--){
                ans[index++] = matrix[i][j];
            }
            step_i++;
            step_j++;
        }
        //行是奇数并且m<n,剩下一行
        if(m%2 != 0 && step_i == m/2){
            for(int j = step_j; j < n - step_j; j++)
                ans[index++] = matrix[step_i][j];
        }
        //列是奇数并且n<m,剩下一列
        else if(n%2 != 0 && step_j == n/2){
            for(int i = step_i; i < m -step_i; i++ )
                ans[index++] = matrix[i][step_j];
        } 
        return ans;    
    }
};

如果用第二种按圈遍历的方法,更简单,只是在大循环内依次进行的四个小循环,需要在最后两个循环添加额外的循环条件

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        vector<int> ans(m*n);
        int left = 0, right = n - 1;
        int top = 0, bottom = m - 1;
        int index = 0;
        while(index < m*n){
            for(int i = left; i <= right; i++){
                ans[index++] = matrix[top][i];
            }
            top++;
            for(int i = top; i <= bottom; i++){
                ans[index++] = matrix[i][right];
            }
            right--;
            //需要添加额外的条件 index < m*n (根据实际题目要求选择对应的约束条件
            for(int i = right; i >=left && index < m*n; i--){
                ans[index++] = matrix[bottom][i];
            }
            bottom--;
            //需要添加额外的条件index < m*n (根据实际题目要求选择对应的约束条件
            for(int i = bottom; i >= top && index < m*n; i--){
                ans[index++] = matrix[i][left];
            }
            left++;
        }
        return ans;
    }
};

为什么要添加这两个?请看下例:
在这里插入图片描述
如果不在内层的四个循环的后两个中添加额外的限制,就会出现多遍历的情况。

剑指 Offer 29. 顺时针打印矩阵

剑指 Offer 29. 顺时针打印矩阵
和54是一样的题目,只是注意m和n可能等于0。

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

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

相关文章

用Node.js吭哧吭哧撸一个运动主页

简单唠唠 某乎问题&#xff1a;人这一生&#xff0c;应该养成哪些好习惯&#xff1f; 问题链接&#xff1a;https://www.zhihu.com/question/460674063 如果我来回答肯定会有定期运动的字眼。 平日里也有煅练的习惯&#xff0c;时间久了后一直想把运动数据公开&#xff0c;…

Vue基本知识

一、vue入门 Vue为前端的框架&#xff0c;免除了原生js的DOM操作。简化书写。 基于MVVM的思想&#xff0c;实现数据的双向绑定&#xff0c;使编程的重点放在数据上。 1、引入vue.js文件 2、定义vue核心对象&#xff0c;定义数据模型 3、编写视图 //1、引入vue.js <scr…

【学习心得】安装cuda/cudann和pytorch

一、查看驱动信息 # 进入CMD输入命令 nvidia-smi 也可以右下角图标打开NVIDIA 设置进行查看 二、下载安装CUDA 1、下载 下载地址 https://developer.nvidia.com/ 2、安装 推荐自定义安装。建议只勾选Cuda&#xff0c;只安装这一个就好&#xff0c;以免报错安装失败。 3、验证…

05 - 研究 .git 目录

查看所有文章链接&#xff1a;&#xff08;更新中&#xff09;GIT常用场景- 目录 文章目录 1. HEAD2. config3. refs4. objects 1. HEAD 2. config 3. refs 4. objects Git对象一共有三种&#xff1a;数据对象 blob、树对象 tree以及提交对象 commit&#xff0c;这些对象都被保…

小白到运维工程师自学之路 第七十四集 (kubernetes基于calico部署应用nginx)

一、详细介绍calico Calico 是一种基于 BGP 的、纯三层的、容器间互通的网络方案。与 OpenStack、Kubenetes、AWS、GCE 等云平台都能够良好的集成。在虚拟化平台中&#xff0c;如 OpenStack、Docker 等都需要实现 workloads 之间互连&#xff0c;但同时也需要对容器做隔离控制…

梅赛德斯-奔驰将成为首家集成ChatGPT的汽车制造商

ChatGPT的受欢迎程度毋庸置疑。OpenAI这个基于人工智能的工具&#xff0c;每天能够吸引无数用户使用&#xff0c;已成为当下很受欢迎的技术热点。因此&#xff0c;有许多公司都在想方设法利用ChatGPT来提高产品吸引力&#xff0c;卖点以及性能。在汽车领域&#xff0c;梅赛德斯…

抓包工具Fiddler下载与安装

一、Fiddler介绍 1.Fiddler简介 Fiddler 是一款免费、灵活、操作简单、功能强大的 HTTP 代理工具&#xff0c;是目前最常用的 HTTP 抓包工具之一。可以抓取所有的 HTTP/HTTPS 包、过滤会话、分析请求详细内容、伪造客户端请求、篡改服务器响应、重定向、网络限速、断点调试等…

GPT-4 如何为我编写测试

ChatGPT — 每个人都在谈论它,每个人都有自己的观点,玩起来很有趣,但我们不是在这里玩— 我想展示一些实际用途,可以帮助您节省时间并提高效率。 我在本文中使用GPT-4 动机 我们以前都见过这样的情况——代码覆盖率不断下降的项目——部署起来越来越可怕,而且像朝鲜一样…

POJ 2429 Miller-rabin素数判定 + pollard-rho质因子分解 + 埃氏筛法

题目不能说是很难&#xff0c;只是用到了许多数学上的知识&#xff08;费马小定理&#xff0c;miller-radin&#xff0c;pollard-rho&#xff09;&#xff0c;还有一些算法上的知识DFS&#xff0c;辗转相除。 我也很菜&#xff0c;一个周末的时间都用在这个题目上了&#xff0…

软考第二章 信息技术发展

本章内容&#xff1a;软件硬件、网络、存储、新技术。 文章目录 2.1 信息技术及其发展2.1.1 计算机硬件2.1.2 计算机网络2.1.3 存储和数据库2.1.4 信息安全 2.2 新一代信息技术2.2.1 物联网2.2.2 云计算2.2.3 大数据2.2.4 区块链2.2.5 人工智能虚拟现实 2.1 信息技术及其发展 …

EXCEL按列查找,最终返回该列所需查询序列所对应的值,VLOOKUP函数

EXCEL按列查找&#xff0c;最终返回该列所需查询序列所对应的值 示例&#xff1a;国标行业分类汉字&#xff0c;匹配id 使用VLOOKUP函数 第一参数&#xff1a;拿去查询的值。 第二参数&#xff1a;匹配的数据。 Ps&#xff1a;Sheet1!$C 21 : 21: 21:E 117 &#xff0c;需要…

通过版本号控制强制刷新浏览器或清空浏览器缓存

背景介绍 在我们做 web 项目时&#xff0c;经常会遇到一个问题就是&#xff0c;需要 通知业务人员&#xff08;系统用户&#xff09;刷新浏览器或者清空浏览器 cookie 缓存的情况。 而对于用户而言&#xff0c;很多人一方面不懂如何操作&#xff0c;另一方面由于执行力问题&am…

屏蔽socket 实例化时,握手阶段报错信息WebSocket connection to ‘***‘ failed

事情起因是这样的&#xff1a; 我们网站是需要socket链接实行实时推送服务&#xff0c;有恶意竞争对手通过抓包或者断网&#xff0c;获取到了我们的socket链接地址&#xff0c;那么他就可以通过java写一个脚本无限链接这个socket地址。形成dos攻击。使socket服务器资源耗尽&…

基于FPGA的FM信号解调

这是本人第一次写博客&#xff0c;写的不好请多多担待。 本次实验是将一个已知的FM信号通过FPGA进行解调&#xff0c;解调出波形并进行FFT得到调制频率fm&#xff0c;并且每一步都通过MATLAB进行波形的验证。 开发工具 VIVADO 2019.2MATLABFM解调 已知FM信号的载波频率fc为22…

基于LVQ神经网络的乳腺肿癌诊断

1.案例背景 1.1 LVQ 神经网络概述 学习向量量化(Learning Vector Quantization,LVQ)神经网络是一种用于训练竞争层的有监督学习(supervisedlearning)方法的输人前向神经网络,其算法是从Kohonen竞争算法演化而来的。LVQ神经网络在模式识别和优化领域有着广泛的应用。 1…

【Sklearn】基于逻辑回归算法的数据分类预测(Excel可直接替换数据))

【Sklearn】基于逻辑回归算法的数据分类预测&#xff08;Excel可直接替换数据&#xff09; 1.模型原理2.模型参数3.文件结构4.Excel数据5.下载地址6.完整代码7.运行结果 1.模型原理 逻辑回归是一种用于二分类问题的统计学习方法&#xff0c;尽管名字中含有“回归”&#xff0c…

Redis 缓存过期及删除

一、Redis缓存过期策略 物理内存达到上限后&#xff0c;像磁盘空间申请虚拟内存(硬盘与内存的swap),甚至崩溃。 内存与硬盘交换 (swap) 虚拟内存&#xff0c;频繁I0 性能急剧下降&#xff0c;会造成redis内存急剧下降&#xff1b; 一般设置物理内存的3/4&#xff0c;在redis…

Java算法_ 二叉树的中序遍历(LeetCode_Hot100)

题目描述&#xff1a;给定一个二叉树的根节点 &#xff0c;返回 它的 中序 遍历 。root 获得更多&#xff1f;算法思路:代码文档&#xff0c;算法解析的私得。 运行效果 完整代码 import java.util.ArrayList; import java.util.List;/*** 2 * Author: LJJ* 3 * Date: 2023/8/…

PyTorch深度学习实践---笔记

PyTorch深度学习实践---笔记 2.线性模型&#xff08;Linear Model&#xff09;2.exercise 3. 梯度下降算法&#xff08;Gradient Descent&#xff09;3.1梯度下降&#xff08;Gradient Descent&#xff09;3.2 随机梯度下降&#xff08;Stochastic Gradient Descent&#xff09…

编译OpenCV问题解决:已经编译OpenCV成功之后无法运行测试代码

报错问题如下&#xff1a; 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 LNK2001 无法解析的外部符号 "void __cdecl cv::imshow(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class c…