已知一组数(其中有重复元素),求这组数可以组成的所有子集中,子集中的各个元素和为整数target的子集,结果中无重复的子集。
例如:nums[]=[10,1,2,7,6,1,5], target=8
结果为:[[1,7],[1,2,5],[2,6],[1,1,6]]
该题无论是回溯法或位运算法,整体时间复杂度为O(2^n)。
为了减小时间复杂度,在搜索回溯过程中应进行剪枝操作:
递归调用时,计算已选择元素的和sum,若sum>target,不再进行更深的搜索,直接返回。
#include<vector>
#include<algorithm>
class Solution
{
public:
Solution() {};
~Solution() {};
std::vector<std::vector<int>> combinationSum2
(std::vector<int>& candidates, int target)
{
std::vector<std::vector<int>> result;
std::vector<int> item;
std::sort(candidates.begin(), candidates.end());
generate(0, candidates, result, item, 0, target);
return result;
}
private:
void generate(int i, std::vector<int>& nums, std::vector<std::vector<int>>& result, std::vector<int> item,
int sum, int target)
{
if (i>=nums.size()||sum>target)
{
return;
}
sum += nums[i];
item.push_back(nums[i]);
if (sum==target&&find(result.begin(),result.end(),item)==result.end())
{
result.push_back(item);
}
generate(i + 1, nums, result, item, sum, target);
sum -= nums[i];
item.pop_back();
generate(i + 1, nums, result, item, sum, target);
}
};
int main()
{
std::vector<int> nums;
nums.push_back(10);
nums.push_back(1);
nums.push_back(2);
nums.push_back(7);
nums.push_back(6);
nums.push_back(1);
nums.push_back(5);
std::vector<std::vector<int>> result;
Solution solve;
result = solve.combinationSum2(nums, 8);
for (unsigned int i = 0; i < result.size(); i++)
{
if (result[i].size()==0)
{
printf("[]");
}
for (unsigned int j = 0; j < result[i].size(); j++)
{
printf("[%d]", result[i][j]);
}
printf("\n");
}
return 0;
}
运行结果为:
[1][1][6]
[1][2][5]
[1][7]
[2][6]
此处若将原来的数进行逆序排序后再进行剪枝回溯也可以。
只需将
std::sort(candidates.begin(), candidates.end());
改为
std::sort(candidates.rbegin(), candidates.rend());
改为逆序后的运行结果为:
[7][1]
[6][2]
[6][1][1]
[5][2][1]