回溯算法
代码模板
思路就是通过横向for循环,纵向递归的形式(递归里面嵌for循环套)
代码模板如下
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择的列表); // 递归
回溯,撤销处理结果
}
}
LeetCode 216.组合总和III
题目链接
思路
还是类似77题的思路,只是把递归的终止条件换了一下
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
result = []
path = []
def backtracking(n, k, startIndex):
if sum(path) == n and len(path) == k:
result.append(path[:])
return
for i in range(startIndex, 10):
path.append(i)
backtracking(n, k, i+1)
path.pop()
backtracking(n, k, 1)
return result
后面看其他回答的时候,发现终止条件是无论sum是不是n,长度到k了都要进行return,所以优化为:
if len(path) == k:
if sum(path) == n:
result.append(path[:])
return
这题同样也可以进行剪枝优化,在77的基础上加上一个如果长度没到k,sum又已经超过n的枝条,就给他return
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
result = []
path = []
def backtracking(n, k, startIndex):
""" 剪枝优化,如果获取的树总和已经大于n了,直接return"""
if sum(path) > n:
return
if len(path) == k:
if sum(path) == n:
result.append(path[:])
return
m = 9 - (k-len(path)) + 1
for i in range(startIndex, m+1):
path.append(i)
backtracking(n, k, i+1)
path.pop()
backtracking(n, k, 1)
return result
LeetCode 17.电话号码的字母组合
题目链接
思路
依旧是模板的形式,无非就是终止条件变了一下,for循环的条件变了一下,以及因为是对两个list做遍历,所以要先对digits遍历取数,再去遍历digits对应的字符串内容。
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
nums = ['', '', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz']
s = ""
result = []
def backtracking(digits, index, s):
if digits == "":
return
if index == len(digits):
result.append(s)
return
digit = int(digits[index])
number = str(nums[digit])
for i in number:
s += i
backtracking(digits, index+1, s)
s = s[:-1]
backtracking(digits, 0 ,s)
return result
反思
在做17题的时候,定义全局变量s,但是回溯里面出现报错
UnboundLocalError: local variable 's' referenced before assignment
原因是在其内部定义了局部变量s,实则这俩不是同一个。所以在递归条件里面加上了s,把这个全局变量也传进去用,问题解决