给定一个数组 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]
]
链接:https://leetcode-cn.com/problems/combination-sum-ii
可以先看看前面一道题组合总数I
和组合总数I思路一样,利用回溯法解。
问题主要出在如何剪枝上。这个代码我觉得可以仔细看看,尤其是剪枝的部分。
先贴出代码。
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
# 给出最后结果
result = []
# 一定要先排序!!
candidates.sort()
def DFS(target, path, step):
# 遍历每个节点
for i in range(step, len(candidates)):
# 这个地方注意!i > step是限制在同一轮(横向),candidates[i] == candidates[i - 1] 是限制不能出现两次,合起来就是在同一轮(横向)过程中不能出现两个同样的数值
if i > step and candidates[i] == candidates[i - 1]:
continue
# 当满足条件时,直接放入result
if target == candidates[i]:
path.append(candidates[i])
result.append(path)
# 可以继续时,注意这里step的取值是往后取
elif target > candidates[i]:
temp = path.copy()
temp.append(candidates[i])
DFS(target-candidates[i], temp, i+1)
else:
break
DFS(target, [], 0)
return result
我们可以先画一个树,
图片来自于题解中liweiwei1419大神的图。
很清楚的可以看到,横向比较,如果这个数在之前出现过(在排好序的情况下),那么我们就要将他剪掉。有两个目标,第一个是确定在横向比较,第二个是出现的数没有出现过。
对于for i in range(step, len(candidates)):
这个循环,很明确,如果i==step那么就说明是刚刚进入这个循环,即将开始迭代,那么当i > step 时,就说明已经在这个循环里了。可以从图上看出来,在同一个循环里就说明是在同一层上。