下面详细介绍 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)