题目
题目描述
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
提示:
1 <= candidates.length <= 100
1 <= candidates[i] <= 50
1 <= target <= 30
题解
解题思路
这个问题与之前的组合总和问题类似,但有一个关键的区别:每个数字在每个组合中只能使用一次,并且解集不能包含重复的组合。这意味着我们需要采取措施来避免产生重复的结果,同时确保我们不会多次使用同一个数字。
为了实现这一点,我们可以先对输入数组candidates
进行排序,然后使用回溯算法(Backtracking)来生成所有可能的组合。在递归过程中,我们将跳过那些会导致重复组合的分支。具体来说,当我们选择了一个数字后,在后续的选择中我们应该跳过所有与它相同的数字,以确保每个组合都是唯一的。
python实现
下面是Python代码实现:
def combinationSum2(candidates, target):
def backtrack(start, target, path):
if target == 0:
result.append(list(path))
return
if target < 0:
return
for i in range(start, len(sorted_candidates)):
# Skip duplicates
if i > start and sorted_candidates[i] == sorted_candidates[i - 1]:
continue
# Choose the number candidates[i]
path.append(sorted_candidates[i])
# Explore further with the chosen number
backtrack(i + 1, target - sorted_candidates[i], path)
# Backtrack, undo the choice
path.pop()
candidates.sort() # Sort to facilitate duplicate skipping
sorted_candidates = candidates
result = []
backtrack(0, target, [])
return result
代码解释
在这段代码中,backtrack
函数接收当前搜索的起始索引start
、剩余的目标值target
以及当前路径path
作为参数。我们首先检查是否达到了目标值或超过了目标值。如果找到了一个有效的组合(即target == 0
),我们就将这个组合添加到结果列表中;如果超出了目标值(即target < 0
),我们就停止进一步探索。
为了避免重复的组合,我们在循环中加入了条件判断if i > start and sorted_candidates[i] == sorted_candidates[i - 1]: continue
。这行代码的作用是跳过与前一个数字相同的数字,除非这是第一次遇到该数字(即i == start
)。通过这种方式,我们可以保证每个组合都是独一无二的。
最后,我们对candidates
进行了排序,这样可以更容易地识别和跳过重复的元素。排序后的数组存储在sorted_candidates
变量中,以便在回溯过程中使用。