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