一 唠嗑
今天有两篇文章!怎么样,惊不惊喜意不意外
今天这两道题昨晚,面试时候子集问题你被问住了,请来找我
二 上题!
面试官问完你上个题,你给出了,他说,那我改一下
Q:已知一个数组,可能有重复元素,给定值target,求出所有子集中,和为target的,不重复的子集。
举例:对于数组【10, 1, 2, 7, 6, 1, 5】,target = 8
则需要返回【【1,7】,【1,2,5】,【2,6】,【1,1,6】】
三 冷静分析
此时你脱口而出:这没区别啊,上道题代码原封不动,我算一下result的和是不是target,是的话,再追加进新数组,不就行了,这种题也拿来面我,渣渣
但你知道,这肯定不是他想要的答案,对吗
那能不能优化呢?
冷静分析:
这道题多了什么?target!
我们在递归&回溯过程中用到了吗?没有!
怎么用?
不卖关子,在深搜算法题中,用的非常广泛的思想-剪枝
当有额外条件时,如果不加以限制,那么将多出很多,不满足额外条件的搜索,没有意义。所以这时候我们要利用条件,在递归回溯时判断,进而决定走向再执行的过程,我们成为剪枝。
那么就很简单了,设置变量sum,当当前sum值>target时,比如10 > 8,根本不需要往下继续递归了,这就降低了时间复杂度,在数据量很大的情况下,剪枝的好处一目了然。
当然,记得回溯时,变量sum也要对应地减去当前元素。
四 完整代码及注释
//
// Created by renyi on 2019/6/26.
//
#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;
void findSubsetsSum(int i, vector<int> &nums, vector<int> &item, vector<vector<int>> &result, set<vector<int>> &res_set, int sum, int target){
if (i >= nums.size() || sum > target){//sum是当前item中元素的和,一旦大于了target,比如10 > 8,就不在递归回溯了,即,剪枝
return;
}
sum += nums[i];//累加sum
item.push_back(nums[i]);//追加进临时数组item
if (res_set.find(item) == res_set.end() && sum == target){//item没在集合中,且sum==target,即找到了和是target的子集
result.push_back(item);//追加结果和集合
res_set.insert(item);
}
findSubsetsSum(i + 1, nums, item, result, res_set, sum, target);
sum -= nums[i];//回溯时,sum要减去nums【i】并从item中删除nums【i】
item.pop_back();
findSubsetsSum(i + 1, nums, item, result, res_set, sum, target);
}
vector<vector<int>> subsets(vector<int> &nums, int target){
vector<vector<int>> result;
vector<int> item;
set<vector<int>> res_set;
sort(nums.begin(), nums.end());//和上道题一样,依然先排序
findSubsetsSum(0, nums, item, result, res_set, 0, target);
return result;
}
int main(){
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);
vector<vector<int>> result;
result = subsets(nums, 8);
for (int i = 0; i < result.size(); i++) {
if (result[i].size() == 0){
printf("[]");
}
for (int j = 0; j < result[i].size(); j++) {
printf("[%d]", result[i][j]);
}
printf("\n");
}
return 0;
}
结果
瞅啥瞅,没了,动动手码起来吧