Leetcode Top100答案和解释 -- Python版本(矩阵)

73. 矩阵置零

python 复制代码
class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        m, n = len(matrix), len(matrix[0])
        first_col_zero = False

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

        for i in range(m - 1, -1, -1):
            for j in range(n - 1, 0, -1):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0
            if first_col_zero:
                matrix[i][0] = 0
  1. 初步思路标题:标记数组法

    • 使用两个布尔数组分别记录需要置零的行和列

    • 需要O(m+n)额外空间,不符合常数空间的要求

  2. 原地标记优化思路

    • 利用矩阵的第一行和第一列作为标记位,记录对应行和列是否需要置零

    • 需要额外两个变量记录第一行和第一列本身是否包含0

    • 从右下角开始遍历修改,避免标记位被提前覆盖

  3. 关键策略优势

    • 空间复杂度优化到O(1),只使用常数个额外变量

    • 两次遍历即可完成标记和修改,时间复杂度O(m×n)

    • 通过逆序遍历避免标记位被覆盖导致的错误

  4. 具体实现

复制代码
class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        m, n = len(matrix), len(matrix[0])
        first_col_zero = False  # 标记第一列是否需要置零

        # 第一次遍历:用第一行和第一列记录需要置零的行和列
        for i in range(m):
            # 检查第一列是否有0
            if matrix[i][0] == 0:
                first_col_zero = True
            # 从第二列开始检查
            for j in range(1, n):
                if matrix[i][j] == 0:
                    matrix[i][0] = 0  # 标记第i行需要置零
                    matrix[0][j] = 0  # 标记第j列需要置零

        # 第二次遍历:根据标记置零(除第一行第一列外)
        for i in range(m - 1, -1, -1):
            # 从最后一列到第二列
            for j in range(n - 1, 0, -1):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0
            # 最后处理第一列
            if first_col_zero:
                matrix[i][0] = 0

54. 螺旋矩阵

python 复制代码
class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        dirs = [[0,1],[1,0],[0,-1],[-1,0]]
        m, n = len(matrix), len(matrix[0])
        ans = []
        i, j, di = 0, 0, 0
        for _ in range(m*n):
            ans.append(matrix[i][j])
            matrix[i][j] = None
            x, y = i + dirs[di][0], j + dirs[di][1]
            if x < 0 or x >= m or y < 0 or y >= n or matrix[x][y] is None:
                di = (di + 1) % 4
            i += dirs[di][0]
            j += dirs[di][1]
        
        return ans
  1. 初步思路标题:分层模拟法

    • 按层模拟,逐层遍历矩阵的外圈到内圈

    • 需要维护四个边界变量,处理边界收缩的逻辑较为复杂

  2. 方向数组+标记法优化思路

    • 使用方向数组表示四个移动方向(右、下、左、上)

    • 访问过的元素标记为None,遇到边界或已访问元素时改变方向

    • 通过取模运算循环切换方向,实现自动转向

  3. 关键策略优势

    • 代码简洁直观,避免复杂的边界判断和循环条件

    • 通过标记法自动处理转向逻辑,无需显式维护边界

    • 一次遍历即可完成,时间复杂度O(m×n)

  4. 具体实现

复制代码
class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        # 方向数组:右、下、左、上
        dirs = [[0,1],[1,0],[0,-1],[-1,0]]
        m, n = len(matrix), len(matrix[0])
        ans = []
        i, j, di = 0, 0, 0  # 当前位置和方向索引
        
        for _ in range(m*n):
            ans.append(matrix[i][j])
            matrix[i][j] = None  # 标记已访问
            
            # 尝试按当前方向移动
            x, y = i + dirs[di][0], j + dirs[di][1]
            # 如果下一个位置越界或已访问,改变方向
            if x < 0 or x >= m or y < 0 or y >= n or matrix[x][y] is None:
                di = (di + 1) % 4  # 顺时针转向下一方向
            
            # 更新位置
            i += dirs[di][0]
            j += dirs[di][1]
        
        return ans

48. 旋转图像

python 复制代码
class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        n = len(matrix)
        for i in range(n):
            for j in range(i, n):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
        
        for row in matrix:
            row.reverse()
  1. 初步思路:直接模拟旋转

    • 最初可能想到创建一个新的矩阵,按照旋转规则将原矩阵的元素放到新矩阵的对应位置

    • 这种方法的时间复杂度为O(n²),但空间复杂度也为O(n²),不满足题目要求的原地修改条件

  2. 优化思路:两次操作转化法

    • 优化方向1:将复杂的旋转操作分解为两个简单的矩阵操作。顺时针旋转90度可以等价为先进行矩阵转置,然后对每一行进行反转

    • 优化方向2:利用矩阵转置(行列互换)和对换行内元素的组合,通过简单的元素交换实现旋转,避免了复杂的坐标计算

  3. 关键策略优势

    • 策略带来的具体好处1:原地操作,只使用常数级别的额外空间,完全满足题目要求

    • 策略带来的具体好处2:算法逻辑清晰简单,通过两个基础矩阵操作的组合,避免了复杂的元素移动计算

  4. 具体实现

复制代码
class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        n = len(matrix)
        # 第一步:矩阵转置(沿主对角线翻转)
        # 只遍历上三角矩阵,将(i,j)与(j,i)交换
        for i in range(n):
            for j in range(i, n):
                matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
        
        # 第二步:每一行反转
        # 对转置后的矩阵的每一行进行左右翻转
        for row in matrix:
            row.reverse()

240. 搜索二维矩阵 II

python 复制代码
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        r, c = len(matrix), len(matrix[0])
        i, j = 0, c - 1

        while i < r and j >= 0:
            if matrix[i][j] > target:
                j -= 1
            elif matrix[i][j] < target:
                i += 1
            else:
                return True
        
        return False
  1. 初步思路标题(暴力遍历法)

    最直接的解法是对整个矩阵进行双重循环遍历,比较每个元素是否等于目标值。这种方法虽然简单直观,但时间复杂度为O(m×n),没有利用矩阵的有序特性,在矩阵规模较大时效率很低。

  2. 优化思路标题(Z字形搜索法)

    • 优化方向1:从矩阵的右上角(或左下角)开始搜索,利用矩阵的行列有序特性,每次比较可以排除一行或一列

    • 优化方向2:通过控制行索引和列索引的移动方向,实现线性时间复杂度的搜索,无需使用二分查找或额外空间

  3. 关键策略优势

    • 策略带来的具体好处1:每次比较都能排除一整行或一整列,搜索路径最多只经过m+n个元素,时间复杂度降为O(m+n)

    • 策略带来的具体好处2:仅使用两个指针变量,空间复杂度为O(1),且代码简洁易懂

  4. 具体实现

复制代码
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        # 获取矩阵的行数和列数
        r, c = len(matrix), len(matrix[0])
        # 从右上角开始搜索
        i, j = 0, c - 1

        # 当行索引在范围内且列索引在范围内时继续搜索
        while i < r and j >= 0:
            # 如果当前元素大于目标值,排除当前列
            if matrix[i][j] > target:
                j -= 1
            # 如果当前元素小于目标值,排除当前行
            elif matrix[i][j] < target:
                i += 1
            # 找到目标值
            else:
                return True
        
        # 搜索完所有可能位置仍未找到
        return False
相关推荐
love530love1 小时前
ComfyUI 报错解决记录:NumPy/SciPy 不兼容与 OpenCV 扩展模块缺失
人工智能·windows·python·opencv·numpy·scipy·layerstyle
每天都在健身的程序员1 小时前
OpenClaw 部署 + 飞书对接完整教程【防踩坑版】
python·openclaw
lcreek1 小时前
LeetCode2208. 将数组和减半的最少操作次数、LeetCode2406.将区间分为最少组数
python·算法
chilavert3182 小时前
程序员面试经典问题解答:java篇-2
开发语言·python
abant22 小时前
leetcode 739 单调栈模板题
算法·leetcode·职场和发展
John Song4 小时前
Python创建虚拟环境的方式对比与区别?
开发语言·python
geovindu4 小时前
python: Bridge Pattern
python·设计模式·桥接模式
搞程序的心海4 小时前
Python面试题(一):5个最常见的Python基础问题
开发语言·python
宝贝儿好7 小时前
【强化学习实战】第十一章:Gymnasium库的介绍和使用(1)、出租车游戏代码详解(Sarsa & Q learning)
人工智能·python·深度学习·算法·游戏·机器学习