首页 > 编程语言 >Day23 第七章 回溯算法part02

Day23 第七章 回溯算法part02

时间:2024-08-09 17:40:07浏览次数:13  
标签:target self part02 Day23 start candidates 回溯 path def

目录

任务

39. 组合总和

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。

思路

回溯问题的关键是抽象出正确的多叉树结构,对于本题要求,每一层是一次选择,第一层就是第一次选择,后续递归中,为了避免重复,遍历自己之后的元素。这种问题最好举例描述比较清晰,下面给出例子。
数组为[2,3,6,7],target为7。我们构造一颗树,其中的某条路径表示每次的选取数值,由于题目说同一个数字可以无限制重复选取,因此上次选取后,下次还可以选,所以递归区间[start,end),但是避免顺序不同的重复组合,(比如选了2,2,3,下次选了3,2,2),所以,我只能选我及我后面的元素。显然,我们不可能无限递归(无限选取)下去,何时终止呢?实际上,只要当前路径累积的值等于target或大于target就说明可以停止了(数组元素为正数)。
由于宽度限制,这张图没有给出后续的过程,比如其中一条符合的路径 2 2 3.

class Solution:
    def __init__(self):
        self.path = []
        self.paths = []
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        self.dfs(candidates,target,0)
        return self.paths
   
    def dfs(self,candidates,target,index): # 每层只选自己和自己之后的元素
        if target < 0: return
        if target == 0:
            self.paths.append(self.path[:])
            return
        
        size = len(candidates)
        for i in range(index,size):
            target -= candidates[i]
            self.path.append(candidates[i])
            self.dfs(candidates,target,i)
            self.path.pop()
            target += candidates[i]     

40. 组合总和II

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。

思路

注意和上题的不同之处,这题的要求是每个数只能使用一次,且数字相同的数可以都使用。为树枝剪枝,考虑只有重复数的第一个节点出现时才采取,使用i或者代码随想录中思路中的used数组均可实现。

#解法1
class Solution:
    def __init__(self):
        self.path = []
        self.paths = []

    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        self.dfs(candidates,target,0)
        return self.paths

    def dfs(self,candidates,target,start): # start每层只选自己之后和自己不同的的元素
        if target < 0: return
        if target == 0:
            self.paths.append(self.path[:])
            return
        
        size = len(candidates)
        for i in range(start,size):
            if i > start and candidates[i] == candidates[i-1]:
                continue
            target -= candidates[i]
            self.path.append(candidates[i])
            self.dfs(candidates,target,i+1)
            self.path.pop()
            target += candidates[i]    

##解法2
class Solution:
    def __init__(self):
        self.path = []
        self.paths = []

    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        used = [False]* len(candidates)
        self.dfs(candidates,target,0,used)
        return self.paths

    def dfs(self,candidates,target,start,used): # start每层只选自己之后和自己不同的的元素
        if target < 0: return
        if target == 0:
            self.paths.append(self.path[:])
            return
        
        size = len(candidates)
        for i in range(start,size):
            if i > 0 and not used[i-1] and candidates[i] == candidates[i-1]:
                continue
            used[i] = True
            target -= candidates[i]
            self.path.append(candidates[i])
            self.dfs(candidates,target,i+1,used)
            self.path.pop()
            target += candidates[i]   
            used[i] = False  

131. 分割回文串

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是
回文串。返回 s 所有可能的分割方案。

思路

本题的思路较难,需要将每层分割抽象成[start,end),
比如 第一次分割可选 [0,end)中的位置,那么在第一次分割选了0位置的情况下,第二次可选[1,end)中的位置。。。
路径应该加字符串的哪些部分是个难点,考虑任意单层递归,[start,i+1)是我们所需的区间。
比如最上层循环,选取[0,end)位置 ,start就是0 ,end为实际选取了哪个节点(的哨兵,因为闭区间),因为回溯后,该层的i变量也会正常遍历,不受其他层影响。
此时我们第x层的某个节点的字符串表示,我们当前第x次选的分割为当前节点所需要的sub字符串.例如,当x=1时,选1这个节点(第一层第二个节点),表示我们第一次选的分割为1时,sub字符串区间为[0,2),然后在每层累加字符串。返回条件是分割索引已经到最后。
实际是在叶子节点的后面虚拟节点返回的。
按照遍历序,先到左下,然后start为len(s)退出,返回叶子层,然后进行当前节点父节点的孩子这一层的循环,再返回父节点,继续循环。。

class Solution:
    def __init__(self):
        self.path = []
        self.paths = []

    def partition(self, s: str) -> List[List[str]]:
        self.dfs(s,0)
        return self.paths
    def dfs(self,s,start):
        if len(s) == start:
            self.paths.append(self.path[:])
        
        for i in range(start,len(s)):
            if self.isPal(s,start,i+1):
                self.path.append(s[start:i+1])
                self.dfs(s,i+1)
                self.path.pop()
    def isPal(self,s,start,end):
        return s[start:end] == s[start:end][::-1]

心得体会

对于前两题可以思考后理解并写出,对于最后一题只能懵懵懂懂的写出,写出后可以理解整个树的处理过程,对于[start:i+1)的思考,试试只考虑单层递归应该比较好理解,对于树的遍历的全部逻辑是写完后分析细节用的,对于题目应该试着去用单层递归的思路去做(包括之前的组合问题),后续需要再做一次关于分割的题。

标签:target,self,part02,Day23,start,candidates,回溯,path,def
From: https://www.cnblogs.com/haohaoscnblogs/p/18350645

相关文章

  • 回溯的简单辅助讲解
    回溯策略我个人其实把回溯看做递归的一个应用,回溯简单来讲就是用递归的方式深度遍历所有的可能,而在某些可能是一个解的时候,就记录,这目前看来和回溯两个字没啥关系,问题就在于,回溯可以解决一些需要我们回退元素并继续尝试的问题。刚才的概念里包含了两个关键词:“回退”,“尝试”。......
  • 字符产part02
    今天学习了字符串的第二部分。翻转字符串里的单词,先整体翻转,再局部翻转。注意移除空格和前头数组中移除元素类似。右旋转,也是先整体再局部翻转。4.翻转字符串里的单词题目:给定一个字符串,逐个翻转字符串中的每个单词。示例1:输入:"theskyisblue"输出:"blueisskyt......
  • 代码随想录day23 || 39 组合总和,40 组合总和2,131 分割回文串
    39组合总和funccombinationSum(candidates[]int,targetint)[][]int{ //思路,组合问题考虑回溯算法,考虑到元素可能重复问题,所以,树的最大深度应该是target/min(candudates)+1 varpath=[]int{} varres=[][]int{} backtracking(target,candidates,&path,&res......
  • Python回溯算法
    回溯算法回溯算法是一种系统的搜索算法,用于解决诸如排列组合、子集生成、图的路径、棋盘问题等问题。其核心思想是通过递归尝试各种可能的解决方案,遇到不满足条件的解时则回退(回溯),继续尝试其他可能性,直到找到所有的解决方案或确认无解。主要步骤:选择路径:在当前步骤选择一个可......
  • C++回溯算法经典例题:四皇后问题
    问题简介:在一个4×4的棋盘上,任意两个皇后都不能处在同一行、同一列任意两个皇后都不能处在同一斜线上(主斜线、反斜线)。题目分析:1.假设第一个皇后在(1,1):    1)在x=3时会卡死            2)在x=4时会卡死        2.假设第一个皇后在(2,1): ......
  • 链表part02
    今天是8月3日,学习了链表的第二部分。交换链表两个节点,考察对next的操作和tmp的灵活运用。删除链表的倒数第N个节点,双指针减少遍历次数。链表相交,移动链表尾对齐,其实就是动长链表的指针。环形链表,记住方法。4.24交换链表两个节点题目:给你一个链表,两两交换其中相邻的节点,并......
  • 数组part02
    2024年8月1日,今天学习了数组的第二部分。1.巩固了昨天的双指针问题,即滑动窗口/双指针;注意,双指针是为了减少for循环,使用的时候小心循环的写法和快慢指针的增长方法。2.学习了数组模拟的螺旋矩阵问题,注意循环不变量;3.学习了前缀和的方法,前缀和常用来解决区间和问题,其实是避免重复......
  • Day15 二叉树Part2 初见回溯(二叉树相关)
    任务110.平衡二叉树给定一个二叉树,判断它是否是平衡二叉树思路典型的树形DP,每个节点向它的左右孩子收集信息,然后利用收集到的信息判断当前节点,最后再将信息传给上层。对于本题,每个节点要判断以自己为根的树是否是平衡二叉树,需要判断3个条件:自己的左子树是否平衡自己的右子......
  • DAY12 二叉树part02
     今日任务二叉树的对称性翻转二叉树二叉树的最大/小深度(递归法)226.翻转二叉树(优先掌握递归)题目链接/文章讲解/视频讲解:https://programmercarl.com/0226.%E7%BF%BB%E8%BD%AC%E4%BA%8C%E5%8F%89%E6%A0%91.html1/**2*Definitionforabinarytreenode.3*s......
  • 三招解锁TNAS便捷访问,一键回溯奥运风采
    巴黎奥运会正火热进行中说起奥运相信很多人都会涌起对08年北京奥运会的无尽回忆那一年,我们怀揣着满腔热情想方设法奔赴北京争相购买可爱的福娃大街小巷回荡着《北京欢迎你》而那届开幕式的壮观景象更是“前无古人,后无来者”场面浩大雄伟气势恢宏高朋满座座无虚席 ......