代码随想录算法训练营Day 25 || 216.组合总和III、17.电话号码的字母组合

216.组合总和III

力扣题目链接(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]]。

17.电话号码的字母组合

力扣题目链接(opens new window)

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

代码随想录算法训练营Day 25 || 216.组合总和III、17.电话号码的字母组合_第1张图片

示例:

  • 输入:"23"
  • 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

 

回溯

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”]。

 

 

你可能感兴趣的:(leetcode,leetcode)