给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
Given a collection of candidate numbers (candidates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
Each number in candidates may only be used once in the combination.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
示例 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 官方题解
Python:
def combinationSum2(candidates, target):
ans, combine, freq = [], [], []
candidates.sort()
for num in candidates:
if not freq or num > freq[-1][0]:
freq.append([num, 1])
else:
freq[-1][1] += 1
def dfs(target, idx):
if target == 0:
ans.append(combine[:])
return
if idx >= len(freq):
return
dfs(target, idx+1)
most = min(target/freq[idx][0], freq[idx][1])
for i in range(1, most+1):
combine.append(freq[idx][0])
dfs(target-i*freq[idx][0], idx+1)
for i in range(1, most+1):
combine.pop()
dfs(target, 0)
return ans
C++:
vector<pair<int, int>> freq;
vector<vector<int>> res;
vector<int> combine;
void dfs(vector<int>& candidates, int target, int idx)
{
if (target == 0)
{
res.emplace_back(combine);
return;
}
if (idx >= freq.size())
{
return;
}
dfs(candidates, target, idx+1);
int most = min(target/freq[idx].first, freq[idx].second);
for (int i = 1; i <= most; ++i)
{
combine.emplace_back(freq[idx].first);
dfs(candidates, target-i*freq[idx].first, idx+1);
}
for (int i = 1; i <= most; ++i)
{
combine.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{
sort(candidates.begin(), candidates.end());
for (auto num : candidates)
{
if (freq.empty() || num > freq.back().first)
{
freq.emplace_back(num, 1);
}
else
{
++freq.back().second;
}
}
dfs(candidates, target, 0);
return res;
}
/***************************************************************/
// 也可以使用上一篇每日一题里的回溯算法
void dfs(vector<int>& candidates, vector<vector<int>>& res, vector<int>& combine, int target, int idx)
{
if (target == 0)
{
// 因为要求不能重复,所以要检查是否重复
if (find(res.begin(), res.end(), combine) == res.end())
{
res.emplace_back(combine);
return;
}
}
if (idx >= candidates.size()) return;
dfs(candidates, res, combine, target, idx+1);
if (target - candidates[idx] >= 0)
{
combine.emplace_back(candidates[idx]);
// 因为要求candidates里的每个数只能被用一次,所以这里要用idx+1
dfs(candidates, res, combine, target-candidates[idx], idx+1);
combine.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<vector<int>> res;
vector<int> combine;
// 提前对candidates进行排序,这样可以保证结果都是递增的
sort(candidates.begin(), candidates.end());
dfs(candidates, res, combine, target, 0);
return res;
}