今天做一个数独和矩阵专题
对python语法的新理解:
- rows = [[0] * 9] * 9
这样会导致改动其中一行, 其他行都会跟着改变, 正确的做法是
rows = [[0] * 9 for _ in range(9)] - 想创建一个3x3x9的数组的话,
[[[0 for _ in range(9)] for _ in range(3)] for _ in range(3)]
得反着来, 一步步加框
[0 for _ in range(dim[-1])]
=> [[0 for _ in range(dim[-1])] for _ in range(dim[-2])]
=> [[[0 for _ in range(dim[-1])] for _ in range(dim[-2])] for _ in range(dim[-3])]
好题有:
- 54: 这种题描述简单, 做起来却不简单
36 数独成立吗(可以有空)
第一想法: 直接遍历, 每一行, 每一列, 每一3x3都保存一个哈希表(直接数组就可以了)
时间:
O
(
81
)
O(81)
O(81) 空间:
O
(
81
∗
3
)
O(81 * 3)
O(81∗3)
class Solution:
def isValidSudoku(self, board: List[List[str]]) -> bool:
rows = [[0] * 9 for _ in range(9)]
cols = [[0] * 9 for _ in range(9)]
grids = [[[0 for _ in range(9)] for _ in range(3)] for _ in range(3)]
for i in range(9):
for j in range(9):
num = board[i][j]
if num == ".":
continue
num = int(num) - 1
if rows[i][num] != 0:
return False
else:
rows[i][num] = 1
if cols[j][num] != 0:
return False
else:
cols[j][num] = 1
x = i // 3
y = j // 3
if grids[x][y][num] != 0:
return False
else:
grids[x][y][num] = 1
return True
惊喜的是能过
看了题解发现一个很有趣的, 对于grid我采用的是三维数组可能有点麻烦, 但我看别人直接用
i
/
3
+
(
j
/
3
)
∗
3
i/3 + (j/3)*3
i/3+(j/3)∗3, 这样一个二维数组就搞定了
37 解数独
解数独的难度直接直线上升了, 放回溯专题好了
54 顺时针螺旋顺序 ,返回矩阵中的所有元素
from typing import List
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
m = len(matrix)
n = len(matrix[0])
res = []
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
direction = 0 # 开始时向右
pos = [0, 0] # 初始位置
visited = [[False for _ in range(n)] for _ in range(m)]
for _ in range(m * n):
i, j = pos
res.append(matrix[i][j])
visited[i][j] = True
# 计算下一个位置
next_i, next_j = i + directions[direction][0], j + directions[direction][1]
# 检查是否需要转向:如果超出边界或下一个位置已经访问过
if not (0 <= next_i < m and 0 <= next_j < n and not visited[next_i][next_j]):
direction = (direction + 1) % 4
next_i, next_j = i + directions[direction][0], j + directions[direction][1]
pos = [next_i, next_j]
return res
遇到了一个很强的方法, 我一开始的想法是, 既然第一排遍历完, 后面就用不上了, 那我能不能遍历完一排, 逆时针旋转90度再删,直到没有.
但这个方法当然时间复杂度就上去了, 其实这个方法的核心就是逐渐缩小边界, 当然你不一定要用旋转并删除啦, 所以一个很优美的不用记录已访问数据的方法是
from typing import List
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
# 记录上下左右边界
m = len(matrix)
n = len(matrix[0])
l = 0
r = n - 1
u = 0
d = m - 1
res = []
while (len(res) < m * n):
# 向右遍历
for i in range(l, r + 1):
res.append(matrix[u][i])
u+=1
# 向下
for i in range(u , d + 1):
res.append(matrix[i][r])
r-=1
# 向左
for i in range(r, l - 1, -1):
res.append(matrix[d][i])
d -=1
# 向上
for i in range(d, u - 1, -1):
res.append(matrix[i][l])
l+=1
return res[:m*n]
48 顺时针旋转正方形矩阵(原地, 不能用其他矩阵)
直接能想到先转置, 再每行反过来
for i in range(len(matrix)):
for j in range(i, len(matrix)):
temp = matrix[i][j]
matrix[i][j] = matrix[j][i]
matrix[j][i] = temp
for row in matrix:
row = row.reverse()
但我犯了个很傻的错,
for j in range(len(matrix))
这不翻转了两次吗
73 把0元素所在的列和行都设为0
难点是空间只能
O
(
1
)
O(1)
O(1)
O
(
m
n
)
O(mn)
O(mn)就是最直接的算法,
O
(
m
+
n
)
O(m+n)
O(m+n)记录哪些行哪些列
但大家都在骂出的题, 我也觉得没啥意义, 先不管吧