给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
在真实的
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思考:
其实这道题,和之前的求无重复数组的题类似,只不过是加了一个限制条件,那么我们在原有的基础上进行一个简单的判断,更改代码如下
def fun(nums,target):
res = []
item = []
i = 0
back(nums,res,item,i)
#只不过是遍历完无重复数组后,加一个判断,看res中是否又满足==target的,加入到我们最后的结果中
for res_ in range(res):
if sum(res_) == target:
result.append(res_)
return result
def back(nums,res,item,i):
if i >= len(nums):
return
item.append(nums[i])
tem = item.copy()
if item not in res:
res.append(tem)
back(nums,res,item,i+1)
item.remove(item[-1])
back(nums,res,item,i+1
考虑上述代码,其回溯思想,算法的时间复杂度为O(2**n),我们对于给定的条件,target并没有充分利用,比如target == 8,nums = [10,1,7,3,4,2,6]
其实我们可以看到,当第一个为10的时候其就大于了target,我们进行了很多大量的无用的重复计算。所以优化上述代码如下
def fun(nums,target):
res = []
item = []
i = 0
summ = 0
back(nums,item,res,i,target,summ)
def back(nums,item,res,i,target,summ):
#首先这里进行更改,当item中的和大于target的时候,返回
if i >= len(nums) or summ > target:
return
item.append(nums[i])
tem = item.copy()
#这里,不仅需要满足无重复,item not in res,且需满足summ == target
if item not in res and summ == target:
res.append(tem)
summ += nums[i]
back(nums,item,res,i+1,target,summ)
summ -= item[-1]
item.remove(item[-1])
back(nums,item,res,i+1,target,summ)
对于优化后的代码,其实还有可以优化的空间,debug我们上述代码,会发现,虽然我们使用了target的条件,会过滤掉很多不必要的计算,其实也就是把每个样本大于target的那部分,过滤掉了,如果在计算之前,将数组进行由大到小的排序,会进一步减少重复计算,因为相当于是一开始就将所有的大于target的值剔除,这样会减少很多递归。