Leetcode 216. 组合总和III
讲解前:
这道题如果掌握了组合那道题的话就变得非常容易了,其实就是多加了一个参数的问题,我们可选的数字从可变的变成了1-9固定,然后呢要找的组合大小还是k,这次多加一个条件就是组合中的数字加起来必须满足条件才能被加入最终答案
class Solution:def combinationSum3(self, k: int, n: int) -> List[List[int]]:res = [] self.backtracking(k, n, res, [], 1, 0)return res def backtracking(self, k, n, res, path, start_index, sum_):# base case when we found if len(path) == k:if sum_ == n:res.append(path[:])returnfor i in range(start_index, 10):path.append(i)self.backtracking(k, n, res, path, i + 1, sum_ + i)path.pop()
讲解后:
讲解之后呢这道题可以继续进行剪枝操作,首先就是和组合那道题是一样的,我们要明白当起始的index和数字末尾之间可以取到的所有数字的长度加上当前path的长度已经小于k的时候,就没必要继续进行递归了,因为凑不齐k个元素了,再其次就是当我们找到的sum以及大于目标值的时候,由于我们是从小到大进行遍历的,所以这时候也可以直接return了,以后再往后只会更大,比如当我们的k是2然后sum是5,在第一层循环的时候我们可以取[1,2], [1,3], [1,4], [1.5],然后到了[1,5]之后,就发现sum已经大于5了,那么再取更多的数字就没意义了,就可以直接进入base case然后return
class Solution:def combinationSum3(self, k: int, n: int) -> List[List[int]]:res = [] self.backtracking(k, n, res, [], 1, 0)return res def backtracking(self, k, n, res, path, start_index, sum_):if sum_ > n:return # base case when we found if len(path) == k:if sum_ == n:res.append(path[:])returnfor i in range(start_index, 11 - (k - len(path))):path.append(i)self.backtracking(k, n, res, path, i + 1, sum_ + i)path.pop()
Leetcode 17. 电话号码组合
讲解前:
这道题需要花一点时间去考虑,但是其实并没有想象中难,首先一定要确定的思路就是我们要明白传入的digits并不会直接利用到代码的逻辑主体中去,这里其实更像是一种给我们几个string然后让我们从每个string中取一个char然后组合成一个新的string,看一共有多少种组合,所以传入的digits其实就应该在一开始就进行处理然后返回给我们一个list of string,再进行后续的处理当我们有了word_list之后,就可以开始回溯算法的思路了,第一步就是直接画图
从这个图中可以清晰的看到按照回溯的规律,我们其实还是在用path来找答案,每一个word中取一个字母,这样加起来一点一点,就会组成一个需要的path例如adg, adh, adi,然后呢对于每一个字母,我们都需要以他作为起点,然后对下一个word进行递归
class Solution:def letterCombinations(self, digits: str) -> List[str]:word_list = []for num in digits:if num == "2":word_list.append("abc")elif num == '3':word_list.append("def")elif num == '4':word_list.append("ghi")elif num == '5':word_list.append("jkl")elif num == '6':word_list.append("mno")elif num == '7':word_list.append("pqrs")elif num == '8':word_list.append("tuv")elif num == '9':word_list.append("wxyz")def backtracking(word_list, path, res, cur_num):# base case # when we reach the last word in the listif cur_num > len(word_list):return# when we found a combo, meaning a string with length of digitsif len(path) == len(word_list):res.append(path)return# recursive case# for each num in the list, add each of its element to the pathfor char in word_list[cur_num]:path = path + charbacktracking(word_list, path, res, cur_num + 1)path = path[:len(path) - 1]path = ''res = []if not digits:return reselse:backtracking(word_list, path, res, 0)return res
讲解后:
看完了卡哥的讲解之后发现了两个我可以改进的地方,第一就是我们没必要在一开始就对digits进行处理用一堆if 语句来把数字翻译成字符串列表,其实就用dict做一个映射就行了,在遍历的时候我们还是直接拿着原始的传入的digits进行遍历,每个数字就直接去dict中取相应的值就可以,这样代码感觉更简洁,然后呢就是我们其实不需要再对path的size进行判断来决定是否加入res了,因为这道题path最后的大小是固定的,一定是和传入的数字多少一样的,所以当我们遇到第一个base case就是已经没有number再去循环的时候,此时的path就正好是我们需要的值了
class Solution:def letterCombinations(self, digits: str) -> List[str]:word_list = []for num in digits:if num == "2":word_list.append("abc")elif num == '3':word_list.append("def")elif num == '4':word_list.append("ghi")elif num == '5':word_list.append("jkl")elif num == '6':word_list.append("mno")elif num == '7':word_list.append("pqrs")elif num == '8':word_list.append("tuv")elif num == '9':word_list.append("wxyz")def backtracking(word_list, path, res, cur_num):# base case # when we reach the last word in the listif cur_num >= len(word_list):res.append(path)return# recursive case# for each num in the list, add each of its element to the pathfor char in word_list[cur_num]:path = path + charbacktracking(word_list, path, res, cur_num + 1)path = path[:len(path) - 1]path = ''res = []if not digits:return reselse:backtracking(word_list, path, res, 0)return res