算法记录 | Day12回溯算法Ⅱ

70 阅读3分钟

算法记录 | Day12回溯算法Ⅱ

回溯法,一般可以解决如下几种问题:

  • 组合问题:N个数里面按一定规则找出k个数的集合
  • 切割问题:一个字符串按一定规则有几种切割方式
  • 子集问题:一个N个数的集合里有多少符合条件的子集
  • 排列问题:N个数按一定规则全排列,有几种排列方式
  • 棋盘问题:N皇后,解数独等等

LeetCode 216-组合总和Ⅲ

题目描述:找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

只使用数字1到9 每个数字最多使用一次 返回所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

题目链接:leetcode.cn/problems/co…

输入: 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 不对应任何字母。

题目链接:leetcode.cn/problems/le…

输入: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
  • 字典的使用
总结
  • 需要再多理解理解