其他分享
首页 > 其他分享> > leetcode回溯问题

leetcode回溯问题

作者:互联网

回溯法也可以叫做回溯搜索法,它是一种搜索的方式
回溯是递归的副产品,只要有递归就会有回溯。所以回溯函数也就是递归函数,指的都是一个函数
因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是穷举的本质。
回溯法解决的问题都可以抽象为树形结构
回溯法一般是在集合中递归搜索,集合的大小构成了树的宽度,递归的深度构成的树的深度

for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。

组合问题

(1)77. 组合


可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。

如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了。
优化过程如下:

已经选择的元素个数:path.size();

还需要的元素个数为: k - path.size();

在集合n中至多可以从该起始位置 : n - (k - path.size()) + 1,开始遍历

为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。(python中是+2,因为右边是开区间)

举个例子,n = 4,k = 3, 目前已经选取的元素为0(path.size为0),n - (k - 0) + 1 即 4 - ( 3 - 0) + 1 = 2。

从2开始搜索都是合理的,可以是组合[2, 3, 4]。

        res = []  #存放符合条件结果的集合
        path = []  #用来存放符合条件结果      
        def backtrack(n, k, startIdx):
            if len(path) == k:
                res.append(path[:])
                return
            for i in range(startIdx, n - (k - len(path)) + 2): #剪枝优化的地方
                path.append(i)  #处理节点
                backtrick(n, k, i + 1)  #递归
                path.pop() #回溯,撤销处理的节点
        backtrick(n, k, 1)
        return res
(2)216. 组合总和 III

注意:与77. 组合 区别之一是本题集合固定的就是9个数[1,...,9],所以for循环固定i<=9

剪枝:

    def __init__(self):
        self.res = []
        self.path = []
        self.curSum = 0

    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        self.backtrack(k, n, 1)
        return self.res
    
    def backtrack(self, k, n, startIdx):
        if self.curSum > n:  # 剪枝
            return
        if len(self.path) == k:  # len(path)==k时不管sum是否等于n都会返回
            if self.curSum == n:
                self.res.append(self.path[:])
            return
        for i in range(startIdx, 9 - (k - len(self.path)) + 2):  # 剪枝
            self.path.append(i)
            self.curSum += i
            self.backtrack(k, n, i + 1)
            self.path.pop()
            self.curSum -=i
(3)17. 电话号码的字母组合

注意:本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而77. 组合 和216.组合总和III 都是是求同一个集合中的组合!
参数指定是有题目中给的string digits,然后还要有一个参数就是int型的index。

注意这个index可不是 77.组合和216.组合总和III 中的startIndx了。

而是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度

class Solution:
    def __init__(self):
        self.res = []
        self.path = ''
        self.letter_map = {
            '2': 'abc',
            '3': 'def',
            '4': 'ghi',
            '5': 'jkl',
            '6': 'mno',
            '7': 'pqrs',
            '8': 'tuv',
            '9': 'wxyz',
        }
    def letterCombinations(self, digits: str) -> List[str]:
        self.res.clear()
        if not digits:
            return []
        self.backtrack(digits, 0)
        return self.res

    def backtrack(self, digits, idx):
        if idx == len(digits):  # 当遍历穷尽后的下一层时
            self.res.append(self.path)
            return
        # 单层递归逻辑 
        letters = self.letter_map[digits[idx]]
        for letter in letters:
            self.path += letter  #处理节点
            self.backtrack(digits, idx + 1)  #递归
            self.path = self.path[: -1]  #回溯,撤销处理的节点

(4)
(5)

标签:digits,return,res,self,问题,回溯,path,leetcode
来源: https://www.cnblogs.com/ttyangY77/p/16266577.html