Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
Each number in C 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.
For example, given candidate set [10, 1, 2, 7, 6, 1, 5]
and target 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
本来这一题用的还是上一题的方法,还超级麻烦,结果时间复杂度很高。
代码如下:
class Solution
{
void dfs(vector<vector<int>>&ans, int target, unordered_map<int, int> &mp, unordered_map<int, int> mk, vector<vector<int>> &vec, vector<int> res)
{
for(auto &i : vec[target])
{
if(mk[target-i]+1 > mp[target-i])
continue;
res.push_back(target - i);
mk[target-i] ++;
if(i != 0)
dfs(ans, i, mp, mk, vec, res);
else
ans.push_back(res);
res.pop_back();
mk[target-i] --;
}
}
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{
sort(candidates.begin(), candidates.end());
vector<bool> dp(target+1, false);
dp[0] = true;
vector<vector<int>> vec(target+1);
unordered_map<int, int> mp;
for(int i=0; i < candidates.size(); ++ i)
{
mp[candidates[i]] ++;
for(int j=target; j>=candidates[i]; --j)
{
if(dp[j-candidates[i]])
{
dp[j] = true;
vec[j].push_back(j-candidates[i]);
}
}
}
vector<vector<int>>ans;
dfs(ans, target, mp, unordered_map<int, int>{}, vec, vector<int>{});
if(ans.size() <= 1)
return ans;
for(auto &i : ans)
sort(i.begin(), i.end());
for(int i=0; i<ans.size(); ++ i)
{
for(int j=i+1; j<ans.size(); ++ j)
{
if(ans[i].size() > ans[j].size())
swap(ans[i], ans[j]);
if(ans[i].size() == ans[j].size())
{
for(int k=0; k<ans[i].size(); ++ k)
{
if(ans[i][k] > ans[j][k])
swap(ans[i], ans[j]);
if(ans[i][k] < ans[j][k])
break;
}
}
}
}
vector<vector<int>>ans1;
ans1.push_back(ans[0]);
for(int i=1; i<ans.size(); ++ i)
{
if(ans[i].size() == ans[i-1].size())
{
bool is = false;
for(int j=0; j<ans[i].size(); ++ j)
if(ans[i][j] != ans[i-1][j])
is = true;
if(is)
ans1.push_back(ans[i]);
}
else
ans1.push_back(ans[i]);
}
return ans1;
}
};
由于这一题,每一个数字只需要出现一次, 那么完全不必要这样,直接进行搜索就可以了。
参考博客:http://www.acmerblog.com/leetcode-solution-combination-sum-ii-6255.html
- 将原数组进行排序。
- 从小到大开始选,选择一个数后,再选取数字从后面开始选。
- 对于同一层的数字,如果前面选取的数字等于现在选取的数字时, 那么在搜索前面的数字时,已经包含这种情况了,所以只需要跳过就好了
class Solution
{
static void dfs(vector<int>&candidates, int target, int bg, vector<vector<int>> &vec, vector<int>&res)
{
if(target == 0)
{
vec.push_back(res);
return;
}
int p = -1;
for(int i=bg; i<candidates.size(); ++ i)
{
if(candidates[i] > target)
return;
if(candidates[i] == p)
continue;
p = candidates[i];
res.push_back(candidates[i]);
dfs(candidates, target-candidates[i], i+1, vec, res);
res.pop_back();
}
}
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{
sort(candidates.begin(), candidates.end());
vector<vector<int>> vec;
vector<int> res;
dfs(candidates, target, 0, vec, res);
return vec;
}
};