算法记录 | Day12回溯算法Ⅱ
回溯法,一般可以解决如下几种问题:
- 组合问题:N个数里面按一定规则找出k个数的集合
- 切割问题:一个字符串按一定规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 排列问题:N个数按一定规则全排列,有几种排列方式
- 棋盘问题:N皇后,解数独等等
LeetCode 216-组合总和Ⅲ
题目描述:找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
只使用数字1到9 每个数字最多使用一次 返回所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了
解题思路
- 这道题与组合问题类似,只是终止条件不同
- 然后按照组合来写。就过了。
我还是很懵啊
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
res = []
path = []
# 确定递归参数 n限定相加之和,k限定组合个数,startidx防止重复?
def backtrack(n,k,startidx):
# 终止条件
if len(path) == k and sum(path) == n:
res.append(path[:])
return
# 单层搜索逻辑 for横向遍历 bactrack纵向遍历
for i in range(startidx,10):
path.append(i)
backtrack(n,k,i+1)
path.pop()
backtrack(n,k,1)
return res
剪枝操作
class Solution:
def __init__(self):
self.res = []
self.path = []
self.sum_n = 0
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
self.backtrack(n,k,1)
return self.res
# 确定递归参数 n限定相加之和,k限定组合个数,startidx防止重复?
def backtrack(self, n,k,startidx):
# 终止条件
if self.sum_n > n:
return
if len(self.path) == k and self.sum_n == n:
self.res.append(self.path[:])
return
# 单层搜索逻辑 for横向遍历 bactrack纵向遍历
# for i in range(startidx,10):
for i in range(startidx, 10 - (k - len(self.path)) + 1):
self.path.append(i)
self.sum_n += i
self.backtrack(n,k,i+1)
self.path.pop()
self.sum_n -= i
难点
- 剪枝操作
- 这里要注意python的函数参数作用域了。一个函数里的参数是没有办法在嵌套的函数里面使用的,如果大家都一起使用一个参数,最好是将所有函数的共有参数放入init当中,相当于整个类的共有参数。
总结
- 回溯算法的模板,还是不太熟,熟练使用才可慢慢理解
LeetCode 17-电话号码的字母组合
题目描述:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
解题思路
- 回溯算法,如何确定递归参数
class Solution:
def __init__(self):
self.letter_map = {
'2': 'abc',
'3': 'def',
'4': 'ghi',
'5': 'jkl',
'6': 'mno',
'7': 'pqrs',
'8': 'tuv',
'9': 'wxyz',
}
self.path = ''
self.res = []
def letterCombinations(self, digits: str) -> List[str]:
if not digits:
return []
self.trackback(digits,0)
return self.res
# 回溯参数 digits 横向遍历某一个数值所对应的字母, 纵向遍历下一个数值对应的字母
def trackback(self, digits,idx):
n = len(digits)
if len(self.path) == n:
self.res.append(self.path)
return
letters = self.letter_map[digits[idx]]
for letter in letters:
self.path += letter
self.trackback(digits,idx+1)
self.path = self.path[:-1]
难点
- 如何确定递归参数,本题是digits和idx
- 字典的使用
总结
- 需要再多理解理解