刷题第二十二天 39. 组合总和 40. 组合总和Ⅱ 131.分割回文串

39. 组合总和

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:

        def back_tracking(result, subset, candidates, target, _sum, start_index):
            if _sum == target:
                result.append(subset.copy())
                return
            if len(subset) > 150 or _sum > target:
                return
            for i in range(start_index,len(candidates)):
                _sum += candidates[i]
                subset.append(candidates[i])
                back_tracking(result, subset, candidates, target, _sum, i)
                _sum -= candidates[i]
                subset.pop()
        
        result = []
        subset = []
        _sum = 0
        back_tracking(result, subset, candidates, target, _sum, 0)
        return result

因为可以选择自身,所以start_index就是为i

题目的边界条件是不让子集长度大于150个,所以设置一个return 条件 len(subset) > 150或者_sum已经大于target了

40. 组合总和Ⅱ

一开始考虑的是排序之后,如果subset在result中了,就不加入。但是发现超时了,还是需要剪枝才可以

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:

        def back_tracking(result, subset, candidates, target, _sum, start_index):
            if _sum == target and subset not in result:
                result.append(subset.copy())
                return
            if _sum > target:
                return
            for i in range(start_index,len(candidates)):
                _sum += candidates[i]
                subset.append(candidates[i])
                back_tracking(result, subset, candidates, target, _sum, i + 1)
                _sum -= candidates[i]
                subset.pop()
        
        result = []
        subset = []
        _sum = 0
        candidates.sort()
        back_tracking(result, subset, candidates, target, _sum, 0)
        return result

剪枝需要考虑的点:

1. 使用used数组来判断当前的值是否被用过了,如果没用过,说明在根节点,并且当前值与前一个值相等,就可以直接跳过,因为相同的情况在前一个值全都考虑过了。

如果用过的话,不能跳过,因为说明在叶子节点。

2.回溯的时候used数组要重新赋值为0

3. 因为不能重复选择当前值,所以每次递归的start_index为当前所取值i + 1

正确代码如下:

这是通过数组来去重,所以每次循环i都是从0开始

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        def back_tracking(result, subset, candidates, target, _sum, start_index):
            if _sum > target:
                return
            elif _sum == target:
                result.append(subset.copy())
                return

            for i in range(start_index,len(candidates)):
                if i > start_index and candidates[i] == candidates[i - 1]:
                    continue
                _sum += candidates[i]
                subset.append(candidates[i])
                back_tracking(result, subset, candidates, target, _sum, i + 1)
                _sum -= candidates[i]
                index = subset.pop()

        
        result = []
        subset = []
        _sum = 0
        candidates.sort()
        back_tracking(result, subset, candidates, target, _sum, 0)
        return result

另外通过start index去重就只要判断i > start_index就可以了, 相当于在叶子上去重

131. 分割回文串

class Solution:
    def partition(self, s: str) -> List[List[str]]:

        def isPalindrome(subsubset):
            left = 0
            right = len(subsubset) - 1
            while(left <= right):
                if subsubset[left] == subsubset[right]:
                    left += 1
                    right -= 1
                else:
                    return False
            return True

        def back_tracking(result, subset, s, start_index):
            if start_index >= len(s):
                result.append(subset.copy())
                return
            
            for i in range(start_index, len(s)):
                if i == start_index:
                    subsubset = s[i]
                elif i > start_index:
                    subsubset = s[start_index:i + 1]
                if isPalindrome(subsubset):
                    subset.append(subsubset)
                else:
                    continue
                back_tracking(result, subset, s, i + 1)
                subset.pop()
        result = []
        subset = []
        start_index = 0
        back_tracking(result, subset, s, start_index)
        return result

几个关键点:

1. 切割和组合类似,都是遍历的时候不能和当前元素重复,所以下一次递归的时候start_index就是i + 1

2. 切割的字串可以用start_index 到 i 的左闭右闭区间表示,因为python字符串的切片是左闭右开的,所以要写成[start_index: i+1]

3. 递归是走树的深度,循环是走树的宽度,所以代码运行的逻辑先是走递归走到底,就是最左边走到最深处,然后回溯返回的过程就是一步步的走树的宽度。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值