矩阵中对角线的遍历问题【C++】

news2025/3/31 23:42:05

1,按对角线进行矩阵排序

题目链接:3446. 按对角线进行矩阵排序 - 力扣(LeetCode)

【题目描述】

对于一个m*n的矩阵grid,要求对该矩阵进行 变换,使得变换后的矩阵满足:

主对角线右上的所有对角线上,元素升序排列。

主对角线左下的所有对角线上,元素降序排列。

【思路】

对于一个矩阵grid,我们可以发现,从右上角到左下角的所有对角线中,同一条对角线上的元素满足:行号i减去列号j是一个定值。

令k=i-j+n,这里加n是为了避免k出现负数。

对于右上角的对角线,k=i-j+n=1。对于左下角的对角线k=m+n-1;

所以,我们可以枚举k=1,2,3,......,m+n-1;相当于从右上角开始,到左下角结束,遍历每条对角线。

 接下来需要求出每条对角线上j的取值范围,从而可以遍历对角线上的元素 。

k=i-j+n——>j=i+n-k。

当i=0时,j取最小值,j=n-k。但是j可能会出现负数,所以最小的j=max(0,n-k)。

当i=m-1时,j取最大值,j=m+n-1-k。但是j可能会超出范围,所以最大的j=min(n-1,m+n-1-k)。

对于一个矩阵,如何区别主对角线的右上和左下???

我们可以通过j的最小值来确定,观察上图可看出,对于主对角线右上的对角线来说,j的最小值都是大于0的,相反,对于主对角线走下的对角线来说,j的最小值都是等于0的。所以可以 以这点来做区分。

接下来就可以进行模拟了:

枚举k=1,2,3......,m+n-1;

求出每条对角线上j的范围。将该对角线上的 元素加入数组 。排序后(升序或者降序)写回原数组。

【代码】

class Solution {
public:
    vector<vector<int>> sortMatrix(vector<vector<int>>& grid) {
        //k=i-j+n;
        int m=grid.size(),n=grid[0].size();
        //右上角k=1
        //左下角k=m+n-1
        for(int k=1;k<m+n;k++)
        {
            //计算当前对角线的最小值和最大值
            int min_j=max(n-k,0);
            int max_j=min(m+n-k-1,n-1);
            vector<int> a;
            for(int j=min_j;j<=max_j;j++)
            {
                a.push_back(grid[k+j-n][j]);
            }
            //主对角线右上 升序排列
            if(min_j>0)
            {
                ranges::sort(a);
            }
            else
            {
                //主对角线左下  降序排列
                ranges::sort(a,greater<int>());
            }
            //写回数组
            for(int j=min_j;j<=max_j;j++)
            {
                grid[k+j-n][j]=a[j-min_j];
            }
        }
        return grid;
    }
};

时间复杂度:O(N^2*logN)

空间复杂度:O(N) 

2,将矩阵按对角线进行排序

题目链接:1329. 将矩阵按对角线排序 - 力扣(LeetCode)

本题和上题思路一致,但是要求每条对角线都按升序排列。

class Solution {
public:
    vector<vector<int>> diagonalSort(vector<vector<int>>& mat) {
        int m=mat.size(),n=mat[0].size();
        for(int k=1;k<m+n;k++)
        {
            int min_j=max(n-k,0);
            int max_j=min(m+n-k-1,n-1);
            vector<int> a;
            for(int  j=min_j;j<=max_j;j++)
            a.push_back(mat[k+j-n][j]);

            ranges::sort(a);
            for(int j=min_j;j<=max_j;j++)
            mat[k+j-n][j]=a[j-min_j];
        }
        return mat;
    }
};

 3,对角线上不同值的数量差

题目链接:2711. 对角线上不同值的数量差 - 力扣(LeetCode)

【题目描述】 

对于一个大小为m*n的矩阵grid,返回一个同等规模的数组ans,其中ans[i][j]表示:

在矩阵grid中,grid[i][j]左上角对角线中不同值的数量和右下角对角线不同值的数量的差值,对最后结果再取绝对值。

【思路1】暴力计算 :

遍历grid[i][j]的每一个元素,计算topLeft[i][j]和bottomRight[i][j]。

首先我们可以定义一个unordered_set容器,遍历元素的时候,将元素加入到该容器中。

计算topLeft[i][j]:从[i,j]位置开始,遍历左上角对角线,进行[i--,j--]操作。直到矩阵的边界。

这个过程中,把遍历到的元素加入到容器中,最终topLeft[i][j]就是容器的大小。

计算bottomRight[i][j]:从[i,j]位置开始,遍历右下角对角线,进行[i++,j++]操作。直到矩阵的边界。这个过程中,把遍历到的元素加入到容器中 ,最终bottomRight[i][j]就是容器的大小。

【思路1代码】

class Solution {
public:
    vector<vector<int>> differenceOfDistinctValues(vector<vector<int>>& grid) {
        int m=grid.size(),n=grid[0].size();
        vector<vector<int>> ans(m,vector<int>(n,0));
        unordered_set<int> st;//天然的去重,容器的大小就是 不同值的数量
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                st.clear();

                //查找左上角 不同值的个数
                for(int x=i-1,y=j-1;x>=0&&y>=0;x--,y--)
                st.insert(grid[x][y]);
                int topLeft=st.size();

                //查找右下角 不同值的个数
                st.clear();
                for(int x=i+1,y=j+1;x<m&&y<n;x++,y++)
                st.insert(grid[x][y]);
                int bottomRight=st.size();

                ans[i][j]=abs(topLeft-bottomRight);
            }
        }
        return ans;
    }
};

时间复杂度:O(m*n*(min(m,n)),m和n分别为grid的行数和列数。

计算一个topLeft和bottomRight需要O(min(m,n))的时间。 

【思路2】

该方法就要使用到前面两道题对 对角线的操作思路。

思路一的方法:对于同一条对角线,会遍历多次。比如求ans[0][0],会遍历一次主对角线,求ans[1][1]的时候,会遍历一次主对角线,求ans[1][1]也会遍历一次主对角线,所以存在多次重复遍历。

我们可以按照前面两道题的思路。

将每条对角线看成是一个一维数组d。

对于d[i]来说:

topLeft[i]是d[i]左侧不同值的数量,我们可以从左向右遍历,将元素加入到哈希集合中,直到遍历到d[i],此时topLeft就是哈希集合的大小。

bottomRight[i]是右侧不同值的数量 ,我们可以从右向左遍历,将元素加入到哈希集合中,直到遍历到d[i],此时bottomRight就是哈希集合的大小。

【思路2代码】

class Solution {
public:
    vector<vector<int>> differenceOfDistinctValues(vector<vector<int>>& grid) {
        int m=grid.size(),n=grid[0].size();
        unordered_set<int> st;
        vector<vector<int>> ans(m,vector<int>(n));
        //枚举k 从1到m+n-1
        //k=i-j+n
        for(int k=1;k<m+n;k++)
        {
            //求出j的范围
            int min_j=max(n-k,0);//i=0时,j=n-k,但不能是负数
            int max_j=min(m+n-k-1,n-1);//i=m-1时,j=m+n-1-k,但不能超出范围
            
            st.clear();
            //计算左侧不同值的数量 topLeft
            //从 左向右遍历
            for(int j=min_j;j<=max_j;j++)
            {
                int i=k+j-n;
                ans[i][j]=st.size(); //topLeft[i][j]=st.size();
                st.insert(grid[i][j]);
            }
            //计算右侧最大值的数量  bottomRight
            //从右向左遍历
            st.clear();
            for(int j=max_j;j>=min_j;j--)
            {
                int i=k+j-n;
                ans[i][j]=abs(ans[i][j]-(int)st.size());//st.size()返回值时size_t
                st.insert(grid[i][j]);
            }
        }
        return ans;
    }
};

时间复杂度:O(m*n),每个单元格访问两次。

4,对角线遍历

题目链接:498. 对角线遍历 - 力扣(LeetCode)

 【思路】

我们前面所讲题的对角线遍历,对角线都是从左上角到右下角的一条线。都是主对角线

而本题 方向相反,都是副对角线。我们可以将数组中的每一行进行翻转,就可以转化成主对角线了。

之后,使用前面的思想,遍历每条对角线。

k=i-j+n;枚举k,从1到m+n-1;

 求出每条对角线j的最大值和最小值。

对于每条对角线,我们可能需要从下到上遍历,也可能需要从上到下遍历。对应的j就需要从大到小遍历,也可能需要从小到大遍历。

我们可以定义一个变量flag,flag=1时从下到上遍历,也就是j从从大到小遍历。

flag=0时,从上到下遍历,也就是j从小到大遍历。

开始时,需要从下到上遍历,flag设为1.

【代码】

class Solution {
public:
    vector<int> findDiagonalOrder(vector<vector<int>>& mat) {
        int m=mat.size(),n=mat[0].size();
        //翻转每一行
        for(auto& v:mat)
        {
            reverse(v.begin(),v.end());
        }
        vector<int> ans;
        int flag=1;
        //k=i-j+n
        //1,2,3......m+n-1
        //枚举k,枚举每一条对角线
        for(int k=1;k<m+n;k++)
        {
            //求出j的最小值和最大值
            int min_j=max(n-k,0);
            int  max_j=min(m+n-k-1,n-1);

            //从下到上遍历  对于j是从大到小遍历
            if(flag)
            {
                for(int j=max_j;j>=min_j;j--)
                {
                    int i=k+j-n;
                    ans.push_back(mat[i][j]);
                }
            }
            else  //从上到下遍历  对应的j从小到大遍历
            {
                for(int  j=min_j;j<=max_j;j++)
                {
                    int i=k+j-n;
                    ans.push_back(mat[i][j]);
                }
            }
            flag^=1;
        }
        return ans;
    }
};

总结:

对角线的遍历(主对角线):对于一个m*n的矩阵。

在同一条对角线上的元素,行号i减去列号j是一个定值。k=i-j+n;

k的值从1开始到m+n-1。就是主对角线从右上角对角线开始,一直到左下角对角线。

遍历对角线时,我们只需求出j的范围即可,i=k+j-n。但需要注意j不能小于0,也不能超出数组的范围。然后就可以对这条对角线进行操作了。

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

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

相关文章

[Lc4_dfs] 解数独 | 单词搜索

目录 1.解数独 题解 2.单词搜索 题解 1.解数独 链接&#xff1a;37. 解数独 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线…

day17 学习笔记

文章目录 前言一、数组的增删改查1.resize函数2.append函数3.insert函数4.delete函数5.argwhere函数6.unique函数 二、统计函数1.amax&#xff0c;amin函数2.ptp函数3.median函数4.mean函数5.average函数6.var&#xff0c;std函数 前言 通过今天的学习&#xff0c;我掌握了num…

自动语音识别(ASR)技术详解

语音识别&#xff08;Automatic Speech Recognition, ASR&#xff09;是人工智能和自然语言处理领域的重要技术&#xff0c;旨在将人类的语音信号转换为对应的文本。近年来&#xff0c;深度学习的突破推动语音识别系统从实验室走入日常生活&#xff0c;为智能助手、实时翻译、医…

git | 版本切换的相关指令

常见指令 git log --oneline #查看历史提交 git tag latest-backup # 对当前的提交进行标记&#xff0c;标记名为latest-backup git checkout -b old-version 55b16aa # 切换到[55b16aa]的提交中&#xff0c;并标记为[old-version]的分支 git checkout master …

19.OpenCV图像二值化

OpenCV图像二值化 图像二值化&#xff08;Binarization&#xff09;是图像预处理中的一种常用技术&#xff0c;其目的是将图像中的像素值分为两个类别——通常是“前景”和“背景”或者说0和255。二值化能够简化图像信息&#xff0c;为后续的形态学处理、边缘检测、目标识别等…

通过Appium理解MCP架构

MCP即Model Context Protocol&#xff08;模型上下文协议&#xff09;&#xff0c;是由Anthropic公司于2024年11月26日推出的开放标准框架&#xff0c;旨在为大型语言模型与外部数据源、工具及系统建立标准化交互协议&#xff0c;以打破AI与数据之间的连接壁垒。 MCP架构与Appi…

分享一个Pyside6实现web数据展示界面的效果图

今天又是有问题直接找DS的一天&#xff0c;每日一问&#xff0c;今天我的问题是“怎么将pyside6生成的界面转成web界面&#xff0c;使用python语言实现web界面”&#xff0c;等了一会&#xff0c;DS给我提供了两种方案&#xff0c;方案如下&#xff1a; 然后&#xff0c;让我们…

FALL靶场通关攻略

1&#xff0c;下载好靶机后打开&#xff0c;通过kali扫描靶机ip和端口&#xff0c;得到靶机ip为192.168.50.144 2&#xff0c;扫描目录 3&#xff0c;访问靶机 4&#xff0c;访问扫描到的test.php,得到缺少GET请求参数的提示 5&#xff0c;使用FUZZ来扫出参数为file 6&#xff…

Mybatis日志模块分析--适配器模式+代理模式

适配器模式 日志在我们开发过程中占据了一个非常重要的地位&#xff0c;是开发和运维管理之间的桥梁&#xff0c;在Java中的日志框架也非常多&#xff0c;Log4j,Log4j2,Apache Commons Log,java.util.logging,slf4j等&#xff0c;这些工具对外的接口也都不尽相同&#xff0c;为…

圆球法线图,图生法线图 图片生成法线图

目录 圆球法线图 根据图片生成法线图 深度图计算法线图 圆球法线图 import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D# 定义球体的参数 radius 1.0 resolution 100# 生成球体表面的点 u np.linspace(0, 2 * np.pi, resoluti…

Java基于SpringBoot的网络云端日记本系统,附源码+文档说明

博主介绍&#xff1a;✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…

【自用记录】本地关联GitHub以及遇到的问题

最近终于又想起GitHub&#xff0c;想上传代码和项目到仓库里。 由于很早之前有在本地连接过GitHub&#xff08;但没怎么用&#xff09;&#xff0c;现在需要重新搞起&#xff08;操作忘得差不多&#xff09;。 在看教程实操的过程中遇到了一些小问题&#xff0c;遂记录一下。 前…

页码设置相关问题记录

Q&#xff1a;中间没有显示页码怎么办&#xff1f; A&#xff1a;“页眉和页脚”-“页码”-“页面底端”-“普通数字2” Q&#xff1a;想让页码在某几节连续怎么办&#xff1f; A&#xff1a; ① 先保证节与节之间插入了“分节符”&#xff08;如何插入分节符和如何显示分节符…

什么是数据集市

数据集市&#xff08;Data Mart&#xff09;是数据管理领域的核心概念&#xff0c;其定义为面向特定业务领域或用户群体的小型数据仓库子集&#xff0c;专注于部门级业务分析&#xff0c;具有快速响应、灵活部署等特点。以下从定义、特点、类型、结构、应用场景及与其他数据架构…

【HC-05蓝牙模块】主要性能指标与通信基础知识

一、HC-05 基础学习视频 HC-05蓝牙串口通信模块调试与应用1 二、HC-05学习视频课件

如何缩短研发周期,降低研发成本?全星APQP软件为您提供解决方案

如何缩短研发周期&#xff0c;降低研发成本&#xff1f;全星APQP软件为您提供解决方案 一、 系统概述 全星研发管理APQP软件系统是一款专为产品研发和质量管控打造的智能化平台&#xff0c;旨在帮助企业高效推进APQP&#xff08;先期产品质量策划&#xff09;流程&#xff0c…

Github Webhook 以及主动式

Github配置 GitHub 默认支持两种 Content-Type: application/json application/x-www-form-urlencoded 特别要注意 Content-Type 我们选择: application/json Flask代码 import os import shutil import subprocess from flask import Flask, request, jsonifyapp = Fla…

猜猜我用的是哪个大模型?我的世界游戏界面简单的模拟效果

我的罗里吧嗦的&#xff0c;根据小朋友的要求&#xff0c;边听边写边输入的提示词&#xff1a; 请生成一段完整的在网页中用html5和javascript代码模拟“我的世界”中游戏场景的互动画面&#xff0c;要求提供若干人物选项可以选择&#xff0c;请自行选择需要使用哪些库或框架来…

基于龙芯3A5000处理器,全国产标准6U VPX板卡解决方案

1&#xff0c;产品功能 本产品为一款高可靠性的基于龙芯3A5000处理器以及 7A2000芯片组的标准6U VPX板卡&#xff0c;具有以太网、SATA、PCIE&#xff0c;以及显示等接口&#xff0c;产品功能框图如图1所示&#xff1a; 图1 系统框图 2&#xff0c;技术指标 序号 项目 指标…

Unity编辑器功能及拓展(3) —[Attribute]特性

在 Unity 中&#xff0c;[Attribute]格式的特性是用于扩展编辑器功能、控制序列化行为和调整 Inspector 显示,进行编辑器拓展的核心工具。 一.基础编辑器拓展 1.基础序列化控制 1.[SerializeField] 强制显示私有变量到Inspector 2.[HideInInspector] 隐藏该字段在Inspect…