[Leetcode] [Tutorial] 矩阵

文章介绍了四个与矩阵操作相关的算法问题及其解决方案:矩阵置零,螺旋矩阵,旋转图像和搜索二维矩阵II。矩阵置零通过使用第一行和第一列作为标记实现;螺旋矩阵按顺时针螺旋顺序返回矩阵元素;旋转图像通过翻转矩阵实现90度旋转;搜索二维矩阵II利用二分查找在每行中寻找目标值。
摘要由CSDN通过智能技术生成


73. 矩阵置零

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

示例:
输入: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]]

Solution

为了解决此问题,我们可以使用矩阵的第一行和第一列来记录其他行和列是否应该被设置为0。但在这之前,我们需要两个标记变量来记录第一行和第一列本身是否应该被设置为0。

class Solution:
    def setZeroes(self, matrix: List[List[int]]) -> None:
        m = len(matrix)
        n = len(matrix[0])

        first_row_has_zero = False
        first_col_has_zero = False

        # Check if first row and first column have zero
        for i in range(m):
            if matrix[i][0] == 0:
                first_col_has_zero = True
                break

        for j in range(n):
            if matrix[0][j] == 0:
                first_row_has_zero = True
                break

        # Use first row and first column as markers
        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

        # Update the rest of the matrix
        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

        # Update first row and first column
        if first_row_has_zero:
            for j in range(n):
                matrix[0][j] = 0

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

54. 螺旋矩阵

给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。

示例:
输入: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]

Solution

class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix:
            return []

        top, bottom = 0, len(matrix) - 1
        left, right = 0, len(matrix[0]) - 1
        order = []

        while top <= bottom and left <= right:
            for i in range(left, right + 1):
                order.append(matrix[top][i])
            top += 1
            
            for i in range(top, bottom + 1):
                order.append(matrix[i][right])
            right -= 1
            
            if top <= bottom:
                for i in range(right, left - 1, -1):
                    order.append(matrix[bottom][i])
                bottom -= 1
            
            if left <= right:
                for i in range(bottom, top - 1, -1):
                    order.append(matrix[i][left])
                left += 1

        return order

对于从左到右遍历上边界和从上到下遍历右边界,由于我们每次都会更新top和right,所以可以保证不会重复遍历。这也就是说,你可以无条件地进行这两个遍历。

而对于从右到左遍历下边界和从下到上遍历左边界,由于在遍历之前,top和right已经被更新了,我们需要检查是否top <= bottom和left <= right来判断是否还有剩余的行或列需要遍历。如果top > bottom或left > right,说明该行或该列已经在之前的遍历中被遍历过了,所以不能再次遍历。

48. 旋转图像

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

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

Solution

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]
        # x轴翻转
        for i in range(n):
            matrix[i] = matrix[i][::-1]

class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        n = len(matrix)

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

        for j in range(0, n):
            for i in range(0, (n - 1) // 2 + 1):
                matrix[i][j], matrix[n - 1 - i][j] = matrix[n - 1 - i][j], matrix[i][j]

另一种解决图像顺时针旋转90度的方法是四元素环状替换。

  • 定义两个层级循环,外循环i表示当前处理的层次,从最外层开始,一直到矩阵的中心;内循环j表示在当前层级中循环替换的起始点,到当前层级的末尾。
  • 在每一层中,都会执行一个四元素的循环替换,即左上角的元素到右上角,右上角的元素到右下角,右下角的元素到左下角,左下角的元素到左上角。
class Solution:
    def rotate(self, matrix: List[List[int]]) -> None:
        n = len(matrix)
        for i in range(n // 2):
            for j in range((n + 1) // 2):
                matrix[i][j], matrix[n - j - 1][i], matrix[n - i - 1][n - j - 1], matrix[j][n - i - 1] = matrix[n - j - 1][i], matrix[n - i - 1][n - j - 1], matrix[j][n - i - 1], matrix[i][j]

240. 搜索二维矩阵 II

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵每行的元素从左到右升序排列,每列的元素从上到下升序排列。

示例:
输入: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

Solution

仅仅是每行从左到右升序,每列从上到下升序,我们不能将整个矩阵视为一个排序的列表并进行常规的二分查找,因为跨行之间的元素并不一定是有序的。

但是,我们可以对每一行都使用一次二分查找,判断 target 是否在该行中,从而判断 target 是否出现。

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        for row in matrix:
            idx = bisect.bisect_left(row, target)
            if idx < len(row) and row[idx] == target:
                return True
        return False

bisect 是一个内置模块,提供了对有序列表进行二分查找的功能。bisect模块包括以下几个主要函数:

bisect_left(list, num, beg, end): 这个函数用于在有序列表中查找数字 num 的插入点,以维持列表的有序性。如果 num 已经存在于列表中,那么插入点是在现有元素之前(即左边)。beg 和 end 参数默认为0和len(list),但可以设置为指定范围。

如果我们观察矩阵的右上角或左下角的元素,我们会发现一个有趣的模式。从右上角开始看:

  • 如果目标值比这个元素小,那么我们可以排除这一列,因为这一列的所有元素都比右上角的元素大(因为它们是升序排列的),所以它们肯定大于目标值。
  • 如果目标值比这个元素大,那么我们可以排除这一行,因为这一行的所有元素都比右上角的元素小(因为它们是升序排列的),所以它们肯定小于目标值。
  • 如果目标值等于这个元素,那么我们找到了目标值。

从左下角看也有类似的模式。这样,我们可以根据目标值和当前元素的比较,来决定是排除行还是列。

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        m, n = len(matrix), len(matrix[0])
        i, j = 0, n - 1
        while i < m and j >= 0:
            if matrix[i][j] == target:
                return True
            elif matrix[i][j] < target:
                i += 1
            else:
                j -= 1
        return False
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值