Day27-两道想破脑袋的[回溯]题目

代码随想录算法训练营Day27

39. Combination Sum

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        ans = []
        def backtrack(path: List[int], sumCur: int, startIndex: int):
            print(path)
            if sumCur == target:
                ans.append(path[:])
                return
            elif sumCur > target:
                return
            for ii in range(startIndex, len(candidates)):
                path.append(candidates[ii])
                backtrack(path, sumCur+candidates[ii], ii)
                path.pop()
        backtrack([], 0, 0)
        return ans
        # 关注如何去重

40. Combination Sum II

都知道组合问题可以抽象为树形结构,那么“使用过”在这个树形结构上是有两个维度的,一个维度是同一树枝上使用过,一个维度是同一树层上使用过。没有理解这两个层面上的“使用过” 是造成大家没有彻底理解去重的根本原因。

那么问题来了,我们是要同一树层上使用过,还是同一树枝上使用过呢?

回看一下题目,元素在同一个组合内是可以重复的,怎么重复都没事,但两个组合不能相同。

所以我们要去重的是同一树层上的“使用过”,同一树枝上的都是一个组合里的元素,不用去重。

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()
        # 回溯算法
        ans = []
        def backtrack(path: List[int], sumCur: int, startIndex: int):
            if sumCur == target:
                ans.append(path[:])
                return
            elif sumCur > target:
                return
            for ii in range(startIndex, len(candidates)):
                if ii > startIndex and candidates[ii] == candidates[ii-1]:
                    continue
                path.append(candidates[ii])
                backtrack(path, sumCur+candidates[ii], ii+1)
                path.pop()
        backtrack([], 0, 0)
        return ans
        # 如何去重: [注意要先排序], 我们要去重的是同一树层上的“使用过”

先对数组 升序 排序,重复的元素一定不是排好序以后相同的连续数组区域的第 1 个元素。也就是说,剪枝发生在:**同一层数值相同的结点第 2、3 … 个结点,因为数值相同的第 1 个结点已经搜索出了包含了这个数值的全部结果. **

131. Palindrome Partitioning

class Solution:
    def partition(self, s: str) -> List[List[str]]:
        ans = []
        def isPalindrome(s:str) -> bool:
            ii, jj = 0, len(s)-1
            while ii < jj:
                if s[ii] != s[jj]:
                    return False
                ii += 1
                jj -= 1
            return True
        def backtrack(path: List[str], startIndex: int):
            if startIndex >= len(s):
                ans.append(path[:])
                return
            for ii in range(startIndex, len(s)):
                if isPalindrome(s[startIndex:ii+1]):
                    path.append(s[startIndex:ii+1])
                    backtrack(path, ii+1)
                    path.pop()
        backtrack([], 0)
        return ans

ans.append(path[:])

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值