力扣Day27(4.1)| 第七章 回溯算法 (39. 组合总和 40.组合总和II 131.分割回文串 )

题一:39. 组合总和

链接

题目链接:
视频链接:
文章链接:

视频总结

关键点

  1. 可重复选取,若有零则会有死循环,还好题目里没有

编程思路

Me:
  1. 画图,三部曲,然后一点点的完善!
卡尔:

力扣实战

思路一:

 class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
            #haha这是我独立通过三部曲分析出的第一道回溯题目!!虽然有错误!但都很快找到了改进!开心
        res = []
        path = []
        def func(candidates,target,sum1,startindex): 
            if sum1>target:	#和越界了直接剪枝
                return
            if sum1==target:	#可重复使用,且不限制组成和的个数,所以退出条件只有sum
                res.append(path[:])
                return
            for i in range(startindex,len(candidates)):
                sum1 += candidates[i]
                path.append(candidates[i])
                func(candidates,target,sum1,i)  #想想开始处和当前i代表的含义之间的关系,这里的开始处就是当前操作数的索引也就是i,所以不是i+1,不是startindex+1,这些都是在猜,不要猜!要去分析!去找联系,此处可以重复使用,所以是i开始,不能重复使用的则为i+1开始
                path.pop()
                sum1-=candidates[i]
        func(candidates,target,0,0)
        return res

#注意去重            
# [2,3,6,7]
# 7
# 输出
# [[2,2,3],[2,3,2],[3,2,2],[7]]
# 预期结果
# [[2,2,3],[7]]
        
# 反思1:

思路二:剪枝

对总集合排序之后,如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历。
在求和问题中,排序之后加剪枝是常见的套路!

 class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
            #haha这是我独立通过三部曲分析出的第一道回溯题目!!虽然有错误!但都很快找到了改进!开心
        res = []
        path = []
        def func(candidates,target,sum1,startindex): 
            candidates.sort()
            if sum1>target:
                return
            if sum1==target:
                res.append(path[:])
                return
            for i in range(startindex,len(candidates)):
                sum1 += candidates[i]
                if sum1 > target: # 如果本层 sum + condidates[i] > target,就提前结束遍历,剪枝(此处即使没剪枝,会在刚进入下次递归时就
           	#直接退出,勉强算是减少了递归的次数,那么递归函数入口的剪枝就没必要了,因为能进来的一定不超过target)
                    return 
                path.append(candidates[i])
                func(candidates,target,sum1,i)  
                path.pop()
                sum1-=candidates[i]
        func(candidates,target,0,0)
        return res

题二:40.组合总和II

链接

题目链接:
视频链接:
文章链接:

视频总结

关键点

  1. 去重数组used

编程思路

Me:
  1. 去重好像还可以通过一个特殊的set自动去重,(不可以,set只可以对数字自动去除,不能对列表,@day7)
卡尔:

在这里插入图片描述

力扣实战

思路一:使用used数组

 class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []
        path = []
        used=[0]*len(candidates)
        candidates.sort()   #因为去重时需要判断相邻是否相等,所以需要排序
        def func(candidates,startindex,target,sum):
            if sum>target:
                return
            if sum == target:
                res.append(path[:])
                return
            for i in range(startindex,len(candidates)):
                if sum+candidates[i]>target:
                    return
                if i>0 and candidates[i]==candidates[i-1] and used[i-1]==0:
                    continue
                sum +=candidates[i]
                used[i]=1
                path.append(candidates[i])
                func(candidates, i+1,target,sum)
                path.pop()
                sum-=candidates[i]
                used[i]=0
        func(candidates,0,target,0)
        return res
        
# 反思1:

思路二:不用used数组!奈斯

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

    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        '''
        类似于求三数之和,求四数之和,为了避免重复组合,需要提前进行数组排序
        '''
        self.paths.clear()
        self.path.clear()
        # 必须提前进行数组排序,避免重复
        candidates.sort()
        self.backtracking(candidates, target, 0, 0)
        return self.paths

    def backtracking(self, candidates: List[int], target: int, sum_: int, start_index: int) -> None:
        # Base Case
        if sum_ == target:
            self.paths.append(self.path[:])
            return
        
        # 单层递归逻辑
        for i in range(start_index, len(candidates)):
            # 剪枝,同39.组合总和
            if sum_ + candidates[i] > target:
                return
            
            # 跳过同一树层使用过的元素
            if i > start_index and candidates[i] == candidates[i-1]:
                continue
            
            sum_ += candidates[i]
            self.path.append(candidates[i])
            self.backtracking(candidates, target, sum_, i+1)
            self.path.pop()             # 回溯,为了下一轮for loop
            sum_ -= candidates[i]       # 回溯,为了下一轮for loop

文档总结

1. 

131.分割回文串
见anki

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值