73.矩阵置零
一、空间复杂度O(m + n)
思路:
根据题目给的示例比较容易想到循环遍历一次记录下为0元素的行和列,再循环遍历两次分别把为0元素对应的行及列上的元素置为0。
代码:
python
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
m = len(matrix)
n = len(matrix[0])
idx_i = []
idx_j = []
for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
idx_i.append(i)
idx_j.append(j)
for i in range(len(idx_i)):
for j in range(n):
matrix[idx_i[i]][j] = 0
for i in range(m):
for j in range(len(idx_j)):
matrix[i][idx_j[j]] = 0
二、空间复杂度O(1)
思路:
从第一种方法利用两个列表来记录改进为使用两个变量来记录。首先,可以使用本身矩阵的第一行和第一列来记录该行该列是否有为0元素,直接原地操作,不新建列表记录;其次,这种记录方式没有考虑本身首行和首列是否存在含0的情况,故增加两个单独变量来记录首行和首列是否存在含0元素,最后单独处理这种情况。
代码:
python
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
m = len(matrix)
n = len(matrix[0])
first_row_has_zero = 0 in matrix[0] # 记录第一行是否包含 0
first_col_has_zero = any(row[0] == 0 for row in matrix) # 记录第一列是否包含 0
# 用第一列 matrix[i][0]保存本列是否有0值
# 用第一行 matrix[0][j]保存本行是否有0值
# 都不遍历首行或首列,因为有先定义的两个变量看了首行首列是否有0
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
# 如果第一行一开始就包含 0,那么把第一行全变成 0
if first_row_has_zero:
for j in range(n):
matrix[0][j] = 0
# 如果第一列一开始就包含 0,那么把第一列全变成 0
if first_col_has_zero:
for row in matrix:
row[0] = 0
参考:力扣灵神题解
记录一下不太熟悉的语法:
- *matrix 将矩阵的每一行解包为独立的参数传递给 zip。
- zip 函数会将这些行的对应位置的元素组合成元组,形成新的列。
54.螺旋矩阵
思路:
分别设置四个边界up,down,left,right用于指代上下左右,按顺时针螺旋顺序用四个循环来遍历这四个边界;新建列表和计数下标,用于记录四个循环遍历到的数来存进去。
注意:
up、down确定行,left、right确定列,下标不要搞混了
代码:
python
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
m, n = len(matrix), len(matrix[0])
up, down, left, right = 0, m - 1, 0, n - 1
count = 0
nums = [0] * m * n
while(True):
for j in range(left, right + 1):
nums[count] = matrix[up][j]
count += 1
up += 1
if up > down:
break
for i in range(up, down + 1):
nums[count] = matrix[i][right]
count += 1
right -= 1
if right < left:
break
for j in range(right, left - 1, -1):
nums[count] = matrix[down][j]
count += 1
down -= 1
if down < up:
break
for i in range(down, up - 1, -1):
nums[count] = matrix[i][left]
count += 1
left += 1
if left > right:
break
return nums
参考:代码随想录
48.旋转图像
整体思路:
整体的思路方法都是先把矩阵转置然后以列对称轴为中心两边元素交换。如果下次回忆不起来就自己用示例画一下
注意:
1、矩阵转置时只要对上三角或下三角进行转置,也就是说,j要么范围为(i + 1, n - 1),要么范围为(0, i - 1),要不然就相当于两次转置转回来了
2、区分偶数列和奇数列进行交换,一开始第一种写法没有加判断条件怎么写也不对,发现偶数会多换一次...真鸡肋啊这笨脑子,而且忘记了可以直接用内置函数交换...
一、两个循环写法
python
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
m, n = len(matrix), len(matrix[0])
# 矩阵转置
for i in range(m):
for j in range(i + 1, n):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
for i in range(m):
for j in range(n // 2 + 1):
if j == n // 2:
continue
matrix[i][j], matrix[i][n - j - 1] = matrix[i][n - j - 1],matrix[i][j]
或者:
python
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
n = len(matrix)
# 第一步:转置
for i in range(n):
for j in range(i): # 遍历对角线下方元素
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
# 第二步:行翻转
for row in matrix:
row.reverse()
参考:灵神
二、一个循环
思路:
之前的两种写法都是分为两个循环,分别进行转置和列交换,一个循环的方法就是把转置和列交换放在一个循环里面,在一行进行完转置的操作之后,就已经可以在这一行以列为中轴进行交换了
代码:
python
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
"""
Do not return anything, modify matrix in-place instead.
"""
m= len(matrix)
for i, row in enumerate(matrix):
for j in range(i + 1, m):
# row[j]相当于matrix[i][j]
row[j], matrix[j][i] = matrix[j][i], row[j]
# 在一行进行完转置的操作之后,就已经可以在这一行以列为中轴进行交换了
row.reverse()
参考:灵神