力扣题目链接(opens new window)
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:
示例 1: 输入: k = 3, n = 7 输出: [[1,2,4]]
示例 2: 输入: k = 3, n = 9 输出: [[1,2,6], [1,3,5], [2,3,4]]
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
result = [] # 存放结果集
self.backtracking(n, k, 0, 1, [], result)
return result
def backtracking(self, targetSum, k, currentSum, startIndex, path, result):
if currentSum > targetSum: # 剪枝操作
return # 如果path的长度等于k但currentSum不等于targetSum,则直接返回
if len(path) == k:
if currentSum == targetSum:
result.append(path[:])
return
for i in range(startIndex, 9 - (k - len(path)) + 2): # 剪枝
currentSum += i # 处理
path.append(i) # 处理
self.backtracking(targetSum, k, currentSum, i + 1, path, result) # 注意i+1调整startIndex
currentSum -= i # 回溯
path.pop() # 回溯
让我们以k=3,n=7为例来看这段代码是如何运行的。
首先,我们调用combinationSum3(3, 7)
。在combinationSum3
函数中,我们创建了一个空列表result
来保存所有找到的组合。然后调用了backtracking(7, 3, 0, 1, [], result)
。
现在,让我们看看backtracking
函数是如何运行的。我们首先检查当前组合(也就是path
列表)的长度是否等于k,以及当前和(也就是currentSum
)是否等于目标和(也就是targetSum
)。因为现在path
是空的,所以长度肯定不等于k,而且当前和也肯定不等于目标和。然后,我们开始一个循环,从1遍历到9。
首先,我们尝试把1添加到path
中,并把1加到当前和中,然后调用backtracking(7, 3, 1, 2, [1], result)
。在这个新的backtracking
函数调用中,我们再次检查path
的长度和当前和,发现它们都还没有达到目标。所以,我们继续循环,这次从2遍历到9。
我们把2添加到path
中,并把2加到当前和中,得到了一个新的组合[1, 2]和新的当前和3。然后我们再次调用backtracking(7, 3, 3, 3, [1, 2], result)
。在这个新的函数调用中,我们还需要选择1个数,并且这个数需要使得当前和增加到7。通过循环尝试所有可能的数,我们最终可以找到4使得组合[1, 2, 4]的和等于7。
因此,[1, 2, 4]就是一个有效的组合,我们把它添加到结果列表中。然后,我们把4从当前组合中移除,并从当前和中减去4,回溯到上一步。接下来,我们会尝试其他的数(比如5、6、7等),但是因为这些数都会使得当前和大于目标和,所以我们可以直接结束搜索。
通过这样的过程,我们最终可以找到所有可能的组合:[[1,2,4]]。
力扣题目链接(opens new window)
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
回溯
class Solution:
def __init__(self):
self.letterMap = [
"", # 0
"", # 1
"abc", # 2
"def", # 3
"ghi", # 4
"jkl", # 5
"mno", # 6
"pqrs", # 7
"tuv", # 8
"wxyz" # 9
]
self.result = []
self.s = ""
def backtracking(self, digits, index):
if index == len(digits):
self.result.append(self.s)
return
digit = int(digits[index]) # 将索引处的数字转换为整数
letters = self.letterMap[digit] # 获取对应的字符集
for i in range(len(letters)):
self.s += letters[i] # 处理字符
self.backtracking(digits, index + 1) # 递归调用,注意索引加1,处理下一个数字
self.s = self.s[:-1] # 回溯,删除最后添加的字符
def letterCombinations(self, digits):
if len(digits) == 0:
return self.result
self.backtracking(digits, 0)
return self.result
假设我们有一个数字字符串"23",我们想找出它可以表示的所有可能的字母组合。
首先,我们调用letterCombinations("23")
。在letterCombinations
函数中,我们调用了backtracking("23", 0)
。
现在,让我们看看backtracking
函数是如何运行的。我们首先检查当前处理的数字的索引是否等于数字字符串的长度。因为一开始我们还没有处理任何数字,所以索引肯定不等于长度。然后,我们开始一个循环,从数字字符串的第一个数字开始。
首先,我们找到数字2对应的所有可能的字母"abc",然后逐一尝试添加到当前的组合中,并递归调用backtracking
函数。例如,我们先尝试添加字母’a’到当前组合中,然后调用backtracking("23", 1)
。
在这个新的backtracking
函数调用中,我们同样会找到下一个数字3对应的所有可能的字母"def",然后逐一尝试添加到当前的组合中,并继续递归调用backtracking
函数。例如,我们先尝试添加字母’d’到当前组合中,然后调用backtracking("23", 2)
。
在这个新的函数调用中,因为当前处理的数字的索引等于数字字符串的长度,所以我们知道已经处理完了所有的数字,并得到了一个有效的组合"ad"。所以我们把这个组合添加到结果列表中。
然后,我们回溯到上一步,尝试下一个字母’e’。通过这样的过程,我们最终可以找到所有可能的组合:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”]。