声明:
今天是中等题第21道题。给定一个数组 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合,candidates
中的每个数字在每个组合中只能使用一次。以下所有代码经过楼主验证都能在LeetCode上执行成功,代码也是借鉴别人的,在文末会附上参考的博客链接,如果侵犯了博主的相关权益,请联系我删除
(手动比心ღ( ´・ᴗ・` ))
正文
题目:给定一个数组 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] ]
解法1。和上一篇博客组合总和I相似的思路,只是递归过程中可选元素不包括当前已经被选择过的元素了,代码如下。
执行用时: 168 ms, 在Combination Sum II的Python3提交中击败了37.76% 的用户
class Solution:
def combinationSum2(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
res = []
path = []
candidates.sort()
self._combinationSum2(candidates, target, 0, path, res)
return res
def _combinationSum2(self, nums, target, index, path, res):
if target == 0 and path not in res: # 如果不加判断是否重复的逻辑的话结果会有重复
res.append(path)
return
if path and target < path[-1]:
return
for i in range(index,len(nums)): # index从i+1开始,说明把当前被target减过(选择过)的元素nums[i]剔除出去了,从i+1开始索引元素
self._combinationSum2(nums, target-nums[i], i+1, path+nums[i], res)
# _combinationSum2版本2,因为上面这个函数的写法是在第一条if语句中去重,其实可以优化一下,把去重写在for循环中,之所以会有重复是因为比如原数组中有2个1,target=8,那么结果会有2个[1,7],但这2个[1,7]中的1不是同一个1,优化代码如下:
def _combinationSum2(self, nums, target, index, path, res):
if target == 0:
res.append(path)
return
if path and target < path[-1]:
return
for i in range(index, len(nums)):
if i>index and nums[i] == nums[i-1]: # i必须>index不然i-1就out of index了
continue
self._combinationSum2(nums, target-nums[i], i+1, path+[nums[i]], res)
解法2。用迭代的方式重现递归的过程,用stack存放每个被遍历元素的状态(index,path,remain)代码如下。
执行用时: 88 ms, 在Combination Sum II的Python3提交中击败了82.31% 的用户
class Solution:
def combinationSum2(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
res = []
path = []
candidates.sort()
n = len(candidates)
stack = [(0,path,target)]
while stack:
index, path, remain = stack.pop()
for i in range(index,n):
if i > index and candidates[i] == candidates[i-1]:
continue
if path and remain < path[-1]:
break
if remain == candidates[i]:
res.append(path + [candidates[i]])
stack += [(i+1, path+[candidates[i]], remain-candidates[i])]
return res
结尾
解法1&解法2:https://blog.csdn.net/qq_17550379/article/details/82591181