40. Combination Sum II(组合总和 II)
1. 题目描述
给定一个数组 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]
]
2. 回溯法(Backtracking)
2.1 解题思路
这题和39. Combination Sum非常的相似,前一题是数组中没有重复数字,但是一个数字可以用N次,这题是数组中有重复数字,但每个数字只能用一次。
两题的整体思路都是相似的,都是使用回溯递归法。不同的是,上一题先重复检查nums[i],后检查下一个数nums[i + 1],因为同一个数可以用N次,而本题先重复检查nums[i + 1],然后检查下一个和nums[i]不同的数字,因为同一个数字只能用一次。
具体的递归流程思路大家可以参考39. Combination Sum的,这里我就不画了。如果有童鞋还是不能理解,可以留言,我再补充一下本题的递归流程图~
2.2 实例代码
class Solution {
vector<vector<int>> ans;
vector<int> temp;
void backTracking(vector<int>& nums, int i, int target) {
if (i >= nums.size() || target - nums[i]) return;
temp.push_back(nums[i]);
if (target - nums[i] == 0) { ans.push_back(temp); temp.pop_back(); return; }
backTracking(nums, i + 1, target - nums[i]);
temp.pop_back();
i++;
while (i < nums.size() && nums[i] == nums[i - 1]) i++; // 跳过当前重复的数字
backTracking(nums, i, target);
}
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
backTracking(candidates, 0, target);
return this->ans;
}
};