六、矩阵问题

news2024/12/23 10:04:24

73、矩阵置零(中等)

题目描述

给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。

示例 1:

输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]

示例 2:

输入:matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]]
输出:[[0,0,0,0],[0,4,5,0],[0,3,1,0]]

提示:

  • m == matrix.length
  • n == matrix[0].length
  • 1 <= m, n <= 200
  • -231 <= matrix[i][j] <= 231 - 1

进阶:

  • 一个直观的解决方案是使用 O(mn) 的额外空间,但这并不是一个好的解决方案。
  • 一个简单的改进方案是使用 O(m + n) 的额外空间,但这仍然不是最好的解决方案。
  • 你能想出一个仅使用常量空间的解决方案吗?

题目思路

对于这道题,要求将一个矩阵中含有0的位置,该行和该列都设置为0。

这道题有点类似于炸弹人的游戏机制,炸弹将一行和一列全部炸裂了。
说到这道题,如果没有空间的限制,很容易实现。

  • 如果是O(mn),非常简单,新开辟一个新的矩阵即可。
  • 如果是O(m+n),也不是很困难,我们利用额外的空间记录对应的行和列是否为0即可。

而如果是常量的空间复杂度,就较为麻烦了,这就需要我们利用现有的空间来记录信息——即使用当前的数组来记录信息。

因此这里,我们的思路是使用当前矩阵的第一行和第一列来记录对应的行和列是否应该为0

不过这里有一个问题:

  • 如果第一行和第一列本身就有0,那么这样的记录就会造成 “污染”,因此,这里我们需要对第一行和第一列做单独的判断。

在算法流程上:

  • 判断第一行和第一列是否应该为0;
  • (1, 1)开始,自上而下、自左向右判断元素num[i][j]是否为0——如果为0,就设置num[i][0]num[0][j]为0;
  • 再次遍历,根据对应第一行和第一列元素的值,对当前的值进行赋值——如果标记为0,则置为0;
  • 最后,根据第一步的判断结果,对第一行和第一列更新数据;

算法代码

1、O(m+n)

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        zero_row, zero_col = [], []
        m, n = len(matrix), len(matrix[0])
        
        for i in range(m):
            for j in range(n):
                if matrix[i][j] == 0:
                    zero_row.append(i)
                    zero_col.append(j)

        for r in zero_row:
            for j in range(n):
                matrix[r][j] = 0
                
        for c in zero_col:
            for i in range(m):
                matrix[i][c] = 0

2、常量空间

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        is_first_row_zero, is_first_col_zero = False, False
        m, n = len(matrix), len(matrix[0])

        for i in range(m):
            if matrix[i][0] == 0:
                is_first_col_zero = True
                break
        for j in range(n):
            if matrix[0][j] == 0:
                is_first_row_zero = True
                break

        for i in range(1, m):
            for j in range(1, n):
                if matrix[i][j] == 0:
                    matrix[i][0] = 0
                    matrix[0][j] = 0

        for i in range(1, m):
            for j in range(1, n):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0

        if is_first_col_zero:
            for i in range(m):
                matrix[i][0] = 0

        if is_first_row_zero:
            for j in range(n):
                matrix[0][j] = 0

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

题目思路

对于这道题,要求我们按照顺时针的方向对矩阵进行遍历,最后转化为一维数组。
在进行数组展开时,我们可以看到顺序是:

  • 向右->向下->向左->向上

如果直接去模拟,整个过程较为繁琐,需要定义每个方向要走多少步等。
这里,我们通过不断重新定义矩阵上下左右边界的方法,来实现循环遍历。

算法具体步骤:

  • 初始化矩阵的上下左右边界;
  • 在上边界(即第一行)从最左移动到最右,此时第一行遍历完后相当于已经用过了,因此可以直接从图中删去,即重新定义上边界(top+1);
    • 若重新定义上边界后,上、下边界交错(top > bottom),说明此时矩阵遍历结束,直接跳出循环,返回结果即可;
    • 若上下不交错,则继续在最右边界处,从最上遍历到最下,逻辑同理;
  • 不断循环上述步骤,直到其中某两条边界交错,跳出循环,返回结果;

算法代码

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        res = []
        # 定义矩阵上下边界
        top, bottom = 0, len(matrix) - 1
        # 定义矩阵左右边界
        left, right = 0, len(matrix[0]) - 1
        while True:
            # 在上边界,从最左遍历到最右
            for i in range(left, right+1):
                res.append(matrix[top][i])
            # 重新设置上边界,如果上边界大于下边界,说明遍历完成,下同
            top += 1
            if top > bottom:
                break
            # 在右边界,从最上遍历到最下
            for i in range(top, bottom+1):
                res.append(matrix[i][right])
            right -= 1
            if right < left:
                break
            # 在下边界,从最右遍历到最左
            for i in range(right, left-1, -1):
                res.append(matrix[bottom][i])
            bottom -= 1
            if bottom < top:
                break
            # 在左边界,从最下遍历到最上
            for i in range(bottom, top-1, -1):
                res.append(matrix[i][left])
            left += 1
            if left > right:
                break

        return res

48、旋转图像(中等)

题目描述

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 1:

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

示例 2:

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

提示:

  • n == matrix.length == matrix[i].length
  • 1 <= n <= 20
  • -1000 <= matrix[i][j] <= 1000

题目思路

对于这道题,本质上是要求我们将一个二维n*n矩阵顺时针旋转90度。

如果我们可以使用额外空间,比较简单直接:

  • 对于矩阵中第i行第j个元素,旋转后,会出现在倒数第i列的第j个位置:
    • matrix_new[j][n - i - 1] = matrix[i][j]

但题目这里不允许使用额外的空间,因此这里我们需要在原二维矩阵进行操作,这里可以直接通过翻转得到。

  • 顺时针旋转:
    • 先通过水平轴翻转,再根据主对角线翻转;
  • 逆时针旋转:
    • 先通过垂直轴翻转, 再根据主对角线旋转;

顺时针:

 1 2 3     7 8 9     7 4 1
 4 5 6  => 4 5 6  => 8 5 2
 7 8 9     1 2 3     9 6 3

逆时针:

 1 2 3     3 2 1     3 6 9
 4 5 6  => 6 5 4  => 2 5 8
 7 8 9     9 8 7     1 4 7

以顺时针为例,之所以能够通过两次翻转得到,是由于:
1、水平轴翻转:

  • matrix[row][col] => matrix[n-row-1][col]

2、主对角线翻转:

  • matrix[n-row-1][col] => matrix[col][n-row-1]

因此最终可以得到:

  • matrix_new[j][n - i - 1] = matrix[i][j]

算法代码

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        matrix.reverse()
        for i in range(len(matrix)):
            for j in range(i+1, len(matrix)):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

附带逆时针:

class Solution48:
    def rotate(self, matrix: List[List[int]]) -> None:
        """
        Do not return anything, modify matrix in-place instead.
        """
        matrix = [list(reversed(x)) for x in matrix]
        for i in range(len(matrix)):
            for j in range(i+1, len(matrix)):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

240、搜索二维矩阵 II(中等)

题目描述

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。

示例 1:

输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5
输出:true

示例 2:

输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20
输出:false

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= n, m <= 300
  • -109 <= matrix[i][j] <= 109
  • 每行的所有元素从左到右升序排列
  • 每列的所有元素从上到下升序排列
  • -109 <= target <= 109

题目思路

对于这道题,要求我们在一个二维数组中找到目标值。

首先,我们可以直接使用暴力搜索的

不过在这道题中该二维数组具备:

  • 每行的元素从左到右升序排列;
  • 每列的元素从上到下升序排列;

因此,我们可以从矩阵的右上角(0, n-1)进行从右向左、从上到下进行查找。

这是由于如果我们从左上角开始,如果matrix[x][y]小于target,那么下一个查找的数字既有可能在右边、也有可能在下边,查找起来就很麻烦。

然而如果我们从右上角开始查找:

  • 如果matrix[x][y] == target,说明查找完成;
  • 如果matrix[x][y] > target,由于每一列的元素都是升序排列的,那么在当前的搜索矩阵中,所有位于第 y 列的元素都是严格大于 target 的,因此我们可以将它们全部忽略,即将 y-1
  • 如果matrix[x][y] < target,由于每一行的元素都是升序排列的,那么在当前的搜索矩阵中,所有位于第 x 行的元素都是严格小于 target 的,因此我们可以将它们全部忽略,即将 x+1

在搜索的过程中,如果我们超出了矩阵的边界,那么说明矩阵中不存在 target

算法代码

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        m, n = len(matrix), len(matrix[0])
        x, y = 0, n-1
        while x < m and y >= 0:
            if matrix[x][y] == target:
                return True
            elif matrix[x][y] > target:
                y -= 1
            else:
                x += 1
        return False

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

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

相关文章

OpenAI工作环境曝光:高薪背后的996;Quora的转变:由知识宝库至信息垃圾场

&#x1f989; AI新闻 &#x1f680; OpenAI工作环境曝光&#xff1a;高薪背后的996 摘要&#xff1a;近日&#xff0c;多位OpenAI匿名员工在求职网站Glassdoor上披露了公司的工作环境和公司文化&#xff0c;包括高薪水和优厚的福利待遇&#xff0c;但同时伴随着996的加班文化…

pdf编辑软件哪个好用?5款PDF编辑器分享

pdf编辑软件哪个好用&#xff1f;PDF编辑软件在现代办公和学术研究中发挥着举足轻重的作用&#xff0c;它们不仅具备基础的编辑和修改功能&#xff0c;还能够支持多种注释工具&#xff0c;帮助我们高效地管理和整理PDF文件。无论是需要调整文档布局、添加文本或图像&#xff0c…

程序员的金三银四求职宝典:如何在关键时期脱颖而出?

个人主页&#xff1a;17_Kevin-CSDN博客 随着春天的脚步渐近&#xff0c;程序员们的求职热潮也随之而来。在这个被称为“金三银四”的招聘季&#xff0c;如何从众多求职者中脱颖而出&#xff0c;成为了许多程序员关注的焦点。本文将为你提供一份全面的求职宝典&#xff0c;助你…

现货大宗软件数据处理模块源码

现货大宗软件数据处理模块源码&#xff1a;揭秘背后的技术魅力 在当今的大数据时代&#xff0c;无论是金融、贸易还是其他领域&#xff0c;数据处理都显得尤为重要。特别是对于现货大宗交易来说&#xff0c;数据处理不仅关乎交易的速度与效率&#xff0c;更直接影响到交易的成…

基于嵌入式的车载导航定位系统设计

一、前言 1.1 项目介绍 【1】项目背景 随着汽车工业的飞速发展和智能化技术的不断突破&#xff0c;车载导航系统作为现代汽车不可或缺的一部分&#xff0c;在人们的日常生活中扮演着越来越重要的角色。它不仅能够提供精确的路线导航&#xff0c;还能提供丰富的地理信息和娱乐…

Java:JVM基础

文章目录 参考JVM内存区域程序计数器虚拟机栈本地方法栈堆方法区符号引用与直接引用运行时常量池字符串常量池直接内存 参考 JavaGuide JVM内存区域 程序计数器 程序计数器是一块较小的内存空间&#xff0c;可以看做是当前线程所执行的字节码的行号指示器&#xff0c;各线程…

mprpc分布式RPC网络通信框架

mprpc 项目介绍 该项目是一个基于muduo、Protobuf和Zookeeper实现的轻量级分布式RPC网络通信框架。 可以把任何单体架构系统的本地方法调用&#xff0c;重构成基于TCP网络通信的RPC远程方法调用&#xff0c;实现同一台机器的不同进程之间的服务调用&#xff0c;或者不同机器…

[ai笔记14] 周鸿祎的ai公开课笔记1

欢迎来到文思源想的ai空间&#xff0c;这是技术老兵重学ai以及成长思考的第14篇分享&#xff01; 本周二月的最后一周&#xff0c;并不是闲下来了&#xff0c;反而是开始进行一些更多的深入实践&#xff0c;关于gpt的主体架构、关于prompt&#xff0c;同时也看了不少书和直播&…

【Linux】基本指令(中)

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:Linux ⚙️操作环境:Xshell (操作系统:CentOS 7.9 64位) 目录 man指令 cp指令 mv指令 cat指令 more指令 less指令 head指令 …

Go语言中的时间控制:定时器技术详细指南

Go语言中的时间控制&#xff1a;定时器技术详细指南 引言定时器基础创建和使用time.Timer使用time.Ticker实现周期性任务定时器的内部机制小结 使用time.Timer实现简单的定时任务创建和启动定时器停止和重置定时器定时器的实际应用小结 利用time.Ticker处理重复的定时任务创建和…

PHP【swoole】

前言 Swoole官方文档&#xff1a;Swoole 文档 Swoole 使 PHP 开发人员可以编写高性能高并发的 TCP、UDP、Unix Socket、HTTP、 WebSocket 等服务&#xff0c;让 PHP 不再局限于 Web 领域。Swoole4 协程的成熟将 PHP 带入了前所未有的时期&#xff0c; 为性能的提升提供了独一无…

[晓理紫]CCF系列会议截稿时间订阅

CCF系列会议截稿时间订阅 关注{晓理紫|小李子}&#xff0c;每日更新最新CCF系列会议信息&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持&#xff01;&#xff01; 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新CCF…

学习使用paddle来构造hrnet网络模型

1、首先阅读了hrnet的网络结构分析&#xff0c;了解到了网络构造如下&#xff1a; 参考博文姿态估计之2D人体姿态估计 - &#xff08;HRNet&#xff09;Deep High-Resolution Representation Learning for Human Pose Estimation&#xff08;多家综合&#xff09;-CSDN博客 最…

3、Redis Cluster集群运维与核心原理剖析

Redis集群方案比较 哨兵模式 在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态&#xff0c;如果master节点异常&#xff0c;则会做主从切换&#xff0c;将某一台slave作为master&#xff0c;哨兵的配置略微复杂&#xff0c;并且性能和高可用性…

用numpy搭建自己的神经网络

搭建之前的基础与思考 构建模型的基本思想&#xff1a; 构建深度学习的过程&#xff1a;产生idea&#xff0c;将idea转化成code&#xff0c;最后进行experiment&#xff0c;之后根据结果修改idea&#xff0c;继续idea–>code–>experiment的循环&#xff0c;直到最终训练…

前后端分离vue+nodejs高校体育运动会比赛系统08fv2-python-php-java

实现了一个完整的高校体育运动会比赛系统系统&#xff0c;其中主要有运动项目模块、学生模块、项目类型模块、用户表模块、token表模块、关于我们模块、收藏表模块、公告信息模块、留言板模块、运动论坛模块、配置文件模块、裁判员模块、比赛成绩模块、比赛报名模块、关于我们模…

Java网络通信TCP

目录 TCP两个核心类 服务端 1.用ServerSocker类创建对象并且手动指定端口号 2.accept阻塞连接服务端与客户端 3.给客户端提供处理业务方法 4.处理业务 整体代码 客户端 1.创建Socket对象&#xff0c;并连接服务端的ip与端口号 2.获取Socket流对象&#xff0c;写入数据…

uniapp 部署h5,pdf预览

1.hubuilderx 打包h5。 2.上传部署包到服务器。 解压部署包&#xff1a;unzip h5.zip 。 3.nginx配置。 user root; worker_processes 1; #worker_cpu_affinity 0001 0010 0100 1000; #error_log logs/error.log; #error_log logs/error.log notice; error_log /var/l…

C#/.NET/.NET Core优秀项目和框架2024年2月简报

前言 公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架&#xff08;每周至少会推荐两个优秀的项目和框架当然节假日除外&#xff09;&#xff0c;公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等&#xff08;打不开或者打开GitHub很慢的同学…

Java基础 - 6 - 面向对象(二)

Java基础 - 6 - 面向对象&#xff08;一&#xff09;-CSDN博客 二. 面向对象高级 2.1 static static叫做静态&#xff0c;可以修饰成员变量、成员方法 2.1.1 static修饰成员变量 成员变量按照有无static修饰&#xff0c;分为两种&#xff1a;类变量、实例变量&#xff08;对象…