ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

leetcode回溯问题

2022-05-13 14:33:58  阅读:204  来源: 互联网

标签:digits return res self 问题 回溯 path 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

剪枝:

  • 已选元素总和如果已经大于n(图中数值为4)了,那么往后遍历就没有意义了,直接剪掉。
  • for循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1就可以了。
    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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有