目录
注意:
继续和b站宝藏up主大雪菜一起刷题
https://www.bilibili.com/video/BV1M4411Q7td
参考刷题视频
17. 电话号码的字母组合
思路:
- 主要是需要枚举所有的字母组合,可以利用循环
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits:
return []
ch = ["abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
res = [""]
for i in range(len(digits)):
now = digits[i]
tmp = []
for c in ch[ord(now)-ord('2')]:
for j in res:
tmp.append(j+c)
res = tmp
return res
79. 单词搜索
思路:
- 由于没有规定起点,所以得依次遍历,看和word是否匹配
- dfs中匹配相同的地方,修改成'.',回溯的时候再还原
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
if len(board)==0 or len(board[0])==0:
return False
for i in range(len(board)):
for j in range(len(board[0])):
if self.dfs(board, word, i, j, 0):
return True
return False
def dfs(self, board, word, x, y, u):
move = [(0,1),(1,0),(0,-1),(-1,0)]
# 必须放在u==len(word)-1之前
if board[x][y]!=word[u]:
return False
if u == len(word)-1:
return True
board[x][y] = '.'
for i in range(4):
newx = x + move[i][0]
newy = y + move[i][1]
if 0<=newx<len(board) and 0<=newy<len(board[0]):
if self.dfs(board, word, newx, newy, u+1):
return True
board[x][y] = word[u]
return False
46. 全排列
思路:
- 利用dfs+回溯,枚举每个位置放哪个数,最后长度达到了len(nums)就直接将当前path加入res
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
visited = [False]*len(nums)
ans = []
self.dfs(nums, 0, [], ans, visited)
return ans
def dfs(self, nums, u, path, ans, visited):
if u == len(nums):
ans.append(path[:])
return
for j in range(len(nums)):
if not visited[j]:
visited[j] = True
path.append(nums[j])
self.dfs(nums, u+1, path, ans, visited)
path.pop()
visited[j] = False
47. 全排列 II
思路:
- 这个题由于要考虑重复的数字,所以先用排序的方法,让一样的数字待在一起,然后一样的数字全排列的起点就不能从头开始,而应该从上一个一样的数字后面开始
- 与上一题相比,这一题是枚举每个数放哪个位置
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
nums = sorted(nums)
ans = []
path = [-1]*len(nums)
visited = [False]*len(nums)
self.dfs(nums, 0, path, ans, 0, visited)
return ans
def dfs(self, nums, u, path, ans, start, visited):
if u == len(nums):
ans.append(path[:])
return
for i in range(start, len(nums)):
if not visited[i]:
visited[i] = True
path[i] = nums[u]
if u+1<len(nums) and nums[u+1]!=nums[u]:
start = 0
else:
start = i+1
self.dfs(nums, u+1, path, ans, start, visited)
visited[i] = False
78. 子集
思路:
- 递归的方法可以解决,同时也可以采用另一种二进制的方法
- 以[1,2,3]为例,有三个数可以表示为000~111,每一位为1代表这个数有,就刚好得到答案
- i>>j&1,意思是i右移j位再和1相与
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = []
for i in range(2**len(nums)):
tmp = []
for j in range(len(nums)):
# print(i<<j)
if (i>>j)&1:
tmp.append(nums[j])
res.append(tmp)
return res
90. 子集 II
思路:
- 因为只是需要得到集合,不用考虑顺序。
- 考虑每个数字出现的次数,用k来统计,每一次dfs得到出现0次、1次....k次的数字
- 每次统计完需要回溯
class Solution:
def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
res = []
nums = sorted(nums)
self.dfs(nums, 0, res, [])
return res
def dfs(self, nums, u, res, path):
if u == len(nums):
res.append(path[:])
return
# 统计有几个nums[u]
k = 0
while k+u < len(nums) and nums[k+u]==nums[u]:
k += 1
for i in range(k+1):
self.dfs(nums, u+k, res, path)
path.append(nums[u])
# 恢复现场
for i in range(k+1):
path.pop()
216. 组合总和 III
思路:
- 利用dfs枚举每一个组合,答案为n就加进ans里
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
res = []
self.dfs(k, 1, n, res, [])
return res
def dfs(self, k, start, n, res, path):
if not k:
if not n:
res.append(path[:])
return
for i in range(start, 10):
path.append(i)
self.dfs(k-1, i+1, n-i, res, path)
path.pop()
52. N皇后 II
思路:
- 首先这个nXn的棋盘上,棋子不能在同一行,不能在同一列,不能在同对角线上
- 对角线可以用x+y,x-y来表示,其中x即第几行,y为第几列,考虑x-y可能为负数,加上一个n即可
- dfs查看每一行哪个地方满足条件,接着dfs下一行,不满足返回探查下一个位置
class Solution:
def totalNQueens(self, n: int) -> int:
res = [0]
col = [False]*(n)
d = [False]*(2*n)
ud = [False]*(2*n)
self.dfs(0, res, n, col, d, ud)
return res[0]
def dfs(self, u, res, n, col, d, ud):
if u == n:
print(res)
res[0] += 1
return
for i in range(n):
if (not col[i]) and (not d[u+i]) and (not ud[u-i+n]):
# print("{} {}".format(i, n))
col[i] = d[u+i] = ud[u-i+n] = True
self.dfs(u+1, res, n, col, d, ud)
col[i] = d[u+i] = ud[u-i+n] = False
473. 火柴拼正方形
思路:
- 这题主要是剪枝的问题
- 从大到小枚举每条边
- 每条边内部的木棒长度规定成从大到小
- 如果当前木棒拼接失败,则跳过接下来所有长度相同的木棒
- 如果当前木棒拼接失败,且是当前边的第一个,则直接剪掉当前分支
- 如果当前木棒拼接失败,且是当前边的最后一个,则直接剪掉当前分支
class Solution:
def makesquare(self, nums: List[int]) -> bool:
# 查看过与否的标记
visited = [False]*len(nums)
# 列表之和
sum_ = sum(nums)
if (sum_ == 0) or (sum_%4 != 0):
return False
# 排序 使一样的数字挤在一起
nums = sorted(nums, reverse = True)
return self.dfs(nums, visited, 0, 0, sum_//4)
def dfs(self, nums, visited, u, cur, length):
# 得到一个满足条件的边
if cur == length:
u += 1
cur = 0
# 四条边都得到了
if u == 4:
return True
i = 0
while i < len(nums):
if not visited[i] and nums[i]<=length-cur:
visited[i] = True
if self.dfs(nums, visited, u, cur+nums[i], length):
return True
visited[i] = False
# 剪枝4
if not cur:
return False
# 剪枝5
if cur+nums[i] == length:
return False
# 剪枝3
if i+1<len(nums) and nums[i+1]==nums[i]:
i += 1
i += 1
return False