python解法:leetcode 39 Combination Sum 回溯加剪枝

下面详细介绍 39. Combination Sum 和 40. Combination Sum II 的python解法,主要用到了回溯加剪枝的思想。

leetcode 39

Given a set of candidate numbers (candidates(without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

The same repeated number may be chosen from candidates unlimited number of times.  每个数字可以使用多次

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations. 允许给出重复的解决方案不

Example 1:

Input: candidates = [2,3,6,7], 
target = 7,
A solution set is:
[
  [7],
  [2,2,3]
]

Example 2:

Input: candidates = [2,3,5], 
target = 8,
A solution set is:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

解法:

递归函数 dfs(candidates,sublist,target,last),其中sublist记录当前满足条件的子数组,last为当前子数组的最后一个元素。

剪枝操作1:目标值小于元素数组的最小元素,则无需继续遍历

剪枝操作2:当前元素大于目标值,则后续元素一定大于目标值(数组已排序),不会满足条件,无需继续遍历

剪枝操作3:若当前数值小于当前sublist的最后一个元素,则继续遍历,防止出现重复解决方案,如[2,2,3],[3,2,2]

class Solution(object):
    def combinationSum(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        self.res = []
        if len(candidates) <= 0:
            return res
        candidates.sort()
        self.dfs(candidates,[],target,0)  # 递归回溯
        return self.res
            
    def dfs(self,candidates,sublist,target,last):  # last表示当前sublist的最后一个元素
        if target == 0:
            self.res.append(sublist) 
        if target < candidates[0]:  # 剪枝操作,目标值小于拥有的最小元素
            return 
        for num in candidates:  # 数字可重复使用,则每次从头遍历
            if num > target:  # 剪枝操作,当当前数值大于目标值,则后续无需遍历
                return 
            if num < last: # 剪枝操作:若当前数值小于当前sublist的最后一个元素,则继续遍历,防止出现重复解决方案,如[2,2,3],[3,2,2]
                continue
            self.dfs(candidates,sublist+[num],target-num,num)
   

leetcode 40 和leetcode39的主要差别在于,给定的数组中有重复的元素;但是在解决方案中不允许重复使用数字。

Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.

Each number in candidates may only be used once in the combination.

Note:

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

Example 1:

Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]
]

Example 2:

Input: candidates = [2,5,2,1,2], target = 5,
A solution set is:
[
  [1,2,2],
  [5]
]

解法:

回溯递归函数dfs(self,candidates,sublist,target,index),index为当前遍历到数组的位置,因为不允许重复使用元素,只可依次遍历。

剪枝操作1: 当target值已经小于0,由于数组中包含负数,所有之间返回

剪枝操作2:保证每个数字只使用一次

class Solution(object):
    def combinationSum2(self, candidates, target):
        """
        :type candidates: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        # 回溯加剪枝
        if len(candidates)<=0:
            return []
        candidates.sort()
        self.res = []
        self.dfs(candidates,[],target,0)
        return self.res
    def dfs(self,candidates,sublist,target,index):
        if target == 0:
            self.res.append(sublist)
            return
        if target < 0:
            return
        for i in range(index,len(candidates)):  # 从当前index开始遍历
            if i != index and candidates[i] == candidates[i-1]: # 保证每个数字只使用一次
                continue
            self.dfs(candidates,sublist+[candidates[i]],target-candidates[i],i+1)

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值