代码随想录算法训练营Day 27| 回溯算法part03 | 39. 组合总和、40.组合总和II、131.分割回文串

代码随想录算法训练营Day 27| 回溯算法part03 | 39. 组合总和、40.组合总和II、131.分割回文串



39. 组合总和

题目链接

一、回溯

class Solution(object):

    def combinationSum(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        # candidates 中的 同一个 数字可以 无限制重复被选取
        # 找出 candidates 中可以使数字和为目标数target的所有 不同组合
        result = [] 
        if not candidates:
            return result
        self.backtracking(candidates,target,0,[],result,0)
        return result
    def backtracking(self,candidates,target,sum,path,result,startindex):
        if sum>target:
            return 
        if sum == target:
            result.append(path[:])
            return
        for i in range(startindex,len(candidates)):
            path.append(candidates[i])
            sum += candidates[i]
            self.backtracking(candidates,target,sum,path,result,i)
            sum -= candidates[i]
            path.pop()

本题需要注意

  1. 加上 if sum>target:的剪枝,不然会溢出。
  2. 因为result 不能有重复组合,所以需要startindex
  3. 因为可以有重复元素,所以递归的startindex为i 而不是i+1

40. 组合总和 II

题目链接

与39.组合总和的区别:
本题candidates 中的每个数字在每个组合中只能使用一次。
本题数组candidates的元素是有重复的,而39.组合总和 (opens new window)是无重复元素的数组candidates

一、用used来去重

class Solution(object):
    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        path = []
        result = []
        candidates.sort()
        used=[0]*len(candidates)
        self.backtracking(candidates,target,0,path,result,0,used)
        return result
    def backtracking(self,candidates,target,sum,path,result,startindex,used):
            if sum>target:
                return 
            if sum == target:
                result.append(path[:])
                return
            for i in range(startindex,len(candidates)):
                if i>0 and candidates[i]==candidates[i-1] and used[i-1]==0:
                    continue
                path.append(candidates[i])
                sum += candidates[i]
                used[i]=1
                self.backtracking(candidates,target,sum,path,result,i+1,used)
                sum -= candidates[i]
                path.pop()
                used[i]=0
                

在这里插入图片描述
在这里插入图片描述

注意:
1.本题需要将candidates先进行排序
2.树层去重,要去重的是“同一树层上的使用过”,如何判断同一树层上元素(相同的元素)是否使用过了呢。
如果candidates[i] == candidates[i - 1] 并且 used[i - 1] == false,就说明:前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1]。
3.前一次使用过的元素,如果后面再使用一定会有重复path出现

二、不用used去重

class Solution(object):
    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        path = []
        result = []
        candidates.sort()
        self.backtracking(candidates,target,0,path,result,0)
        return result
    def backtracking(self,candidates,target,sum,path,result,startindex):
            if sum>target:
                return 
            if sum == target:
                result.append(path[:])
                return
            for i in range(startindex,len(candidates)):
                if i>startindex and candidates[i]==candidates[i-1]:
                    continue
                path.append(candidates[i])
                sum += candidates[i]
                self.backtracking(candidates,target,sum,path,result,i+1)
                sum -= candidates[i]
                path.pop()

131.分割回文串

题目链接

在这里插入图片描述

一、组合问题+判断回文


class Solution(object):

    def partition(self, s):
       '''
        递归用于纵向遍历
        for循环用于横向遍历
        当切割线迭代至字符串末尾,说明找到一种方法
        类似组合问题,为了不重复切割同一位置,需要start_index来做标记下一轮递归的起始位置(切割线)
        '''
        result=[]
        self.backtracking(s,0,[],result)
        return result
    def backtracking(self,s,startindex,path,result):
        if startindex == len(s):
            result.append(path[:])
            return
        for i in range(startindex,len(s)):
            if self.isPalindrome(s,startindex,i):
                path.append(s[startindex:i+1])
                self.backtracking(s,i+1,path,result)
                path.pop()
    def isPalindrome(self,s,start,end):
        i = start
        j = end
        while(i<j):
            if s[i]!=s[j]:
                return False
            i+=1
            j-=1
        return True

注意点:

  1. 切割问题可以抽象为组合问题
  2. 如何模拟那些切割线 :模拟切割线,其实就是index是上一层已经确定了的分割线,i是这一层试图寻找的新分割线
  3. 切割问题中递归如何终止 :index = 字符串的长度就是切割到最后了即终止
  4. 在递归循环中如何截取子串 :子串其实就是从index到 i 的那一段字符串
  5. 如何判断回文:双指针判断
  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值