练习
37. 解数独
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
rows = [[False] * 9 for _ in range(9)]
cols = [[False] * 9 for _ in range(9)]
cell = [[False] * 9 for _ in range(9)]
cell_i = lambda i, j: (i // 3) * 3 + (j // 3)
for i in range(9):
for j in range(9):
if board[i][j] == '.': continue
n = int(board[i][j]) - 1
rows[i][n] = cols[j][n] = cell[cell_i(i, j)][n] = True
def dfs(x, y):
if x == 9: return True
if y == 9: return dfs(x + 1, 0)
if board[x][y] != '.': return dfs(x, y + 1)
for i in range(9):
if not rows[x][i] and not cols[y][i] and not cell[cell_i(x, y)][i]:
rows[x][i] = cols[y][i] = cell[cell_i(x, y)][i] = True
board[x][y] = str(i + 1)
if dfs(x, y + 1): return True
rows[x][i] = cols[y][i] = cell[cell_i(x, y)][i] = False
board[x][y] = '.'
return False
dfs(0, 0) 39. 组合总和
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
ans = []
def dfs(cur, t):
if t < 0: return
if t == 0: ans.append(cur); return
for x in candidates:
if (len(cur) > 0 and cur[-1] or 0) <= x <= t: dfs(cur + [x], t - x)
dfs([], target)
return ans 题目说如果两个结果中每个所选数字的数量都相同,那么这两个结果等价。也就是说不要求顺序,每一个结果都是 set 而非 list,只不过用 list 存放;是组合而非排列。
中间的条件 (len(cur) > 0 and cur[-1] or 0) <= x <= t 保证产生的序列是递增的,这样选择的是唯一的。
40. 组合总和 II
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
ans = set()
n = len(candidates)
candidates.sort()
def dfs(cur, idx, t):
if t == 0: ans.add(tuple(cur)); return
if t < 0 or idx >= n: return
for i in range(idx, n):
x = candidates[i]
if x <= t: dfs(cur + [x], i + 1, t - x)
dfs([], 0, target)
return [list(x) for x in ans]上面的写法对于这个用例会 TLE:[1] * x, 30。需要先想清楚这个 dfs 执行过程中产生的树是什么样子的,然后剪枝。
感谢 liweiwei1419 大佬提供的剪枝思路。简单来说就是同层的相同的都给剪掉,不同层的相同的当然不用管,可以详细看评论区。
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
ans = set()
n = len(candidates)
candidates.sort()
def dfs(cur, idx, t):
if t == 0: ans.add(tuple(cur)); return
if t < 0 or idx >= n: return
for i in range(idx, n):
if i > idx and candidates[i] == candidates[i - 1]: continue
x = candidates[i]
if x <= t: dfs(cur + [x], i + 1, t - x)
dfs([], 0, target)
return [list(x) for x in ans]282. 给表达式添加运算符
需要注意的细节:
- 以 0 开头的只有 ‘0’ 才行,其他都不行。
- 只是二元运算,第一个数字前面没有符号或操作。
class Solution:
def addOperators(self, num: str, target: int) -> List[str]:
n = len(num)
ans = []
def dfs(pre, cur, idx, res):
# 上一个数,当前算数结果,下一个的下标,当前字符串结果
if idx == n:
if cur == target: ans.append(res)
return
for slen in range(1, n - idx + 1):
cur_s = num[idx: idx + slen]
cur_num = int(cur_s)
if cur_s[0] == '0' and len(cur_s) != 1: return
if idx == 0:
dfs(cur_num, cur + cur_num, idx + slen, res + cur_s)
else:
dfs(cur_num, cur + cur_num, idx + slen, res + "+" + cur_s)
dfs(-cur_num, cur - cur_num, idx + slen, res + "-" + cur_s)
dfs(pre * cur_num, cur - pre + pre * cur_num, idx + slen, res + "*" + cur_s)
dfs(0, 0, 0, "")
return ans