算法之回溯

回溯

回溯和dfs关系密切

DFS基本思想:

  1. 本质是遍历决策树
  2. 关注路径选择列表结束条件
  3. 结合回溯:重点是撤销选择
1
2
3
4
5
6
7
8
9
10
res = []
def dfs(路径, 选择列表):
if 满足结束条件:
res.append(路径)
return

for 选择 in 选择列表:
做选择
dfs(路径, 选择列表)
撤销选择

全排列

注意res.append(path[:]):是path的一个拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
def dfs(depth,size,path,seen):
if depth==size:
res.append(path[:])
for i in range(size):
if not seen[i]:
seen[i]=1
path.append(nums[i])
dfs(depth+1,size,path,seen)
seen[i]=0
path.pop()

size=len(nums)
seen=[0]*size
res=[]
dfs(0,size,[],seen)
return res

注意,这里当if depth==size:时没有return,虽然下面的for函数即使运行,也会因为seen[i]=1,而不会对结果造成影响,但这是很不好的习惯

最好在dfs结束时,加上return

其实也可以用内置的permutations函数:

1
2
3
4
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res=[list(t)for t in permutations(nums)]
return res

电话号码的字母组合

选择列表为:dic[str(digits[depth])]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
dic={'2':['a','b','c'],'3':['d','e','f'],'4':['g','h','i'],'5':['j','k','l'],'6':['m','n','o'],'7':['p','q','r','s'],'8':['t','u','v'],'9':['w','x','y','z']}
res=[]
def dfs(depth,size,path,seen):
if depth==size:
res.append(''.join(path[:]))
return
for i in dic[str(digits[depth])]:
seen[i]=1
path.append(i)
dfs(depth+1,size,path,seen)
seen[i]=0
path.pop()

seen=defaultdict(int)
size=len(digits)
if not size:return []
dfs(0,size,[],seen)
return res

括号生成

当左括号不多于n时,可以添加左括号

当左括号数量大于右括号时,可以添加右括号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
def dfs(depth,path,cnt):
if depth==2*n:
if cnt==0:res.append(''.join(path[:]))
return
for x in ('(',')'):
if x=='(' and cnt>=n:continue
if x==')' and cnt<=0:continue
path.append(x)
if x=='(':
cnt+=1
else:
cnt-=1
dfs(depth+1,path,cnt)
if x=='(':
cnt-=1
else:
cnt+=1
path.pop()


res=[]
dfs(0,[],0)
return res

组合总和

since list is an unhashable type, we use Counter to remove duplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res=[]
def dfs(sum,path):
if sum==target:
flag=True
for r in res:
if len(r)==len(path):
if Counter(r)==Counter(path):
flag=False
break
if flag:res.append(path[:])
return
if sum>target:return
for c in candidates:
path.append(c)
dfs(sum+c,path)
path.pop()
dfs(0,[])
return res
不要打赏,只求关注呀QAQ