题目大意
输出在一个数组中选出几个数组成一个整数的不重复具体方案
最初思路
观察到目标数字最大不超过30,且原数组中最小数为1,故一个合法方案至多不超过30个数。可以排序后使用爆搜剪枝,由于需要不重复的方案用set维护。
class Solution {
public:
int n;
vector<vector<int>>res;
set<vector<int>>s;
void dfs(int step,int t,vector<int>temp,vector<int>c)
{
//cout<<t<<endl;
if(t==0)
{
//cout<<t<<endl;
// for(auto i:temp)cout<<i<<" ";
// cout<<endl;
s.insert(temp);
return ;
}
if(step==n)return ;
dfs(step+1,t,temp,c);
if(t-c[step]>=0)
{
temp.push_back(c[step]);
dfs(step+1,t-c[step],temp,c);
}
}
vector<vector<int>> combinationSum2(vector<int>& c, int t) {
n=c.size();
vector<int>temp;
sort(c.begin(),c.end());
dfs(0,t,temp,c);
for(auto i:s)res.push_back(i);
return res;
}
};
这个思路没有考虑到有多个1的情况如:
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
30
所以会导致超时,发现仅有一种方案,但是会被重复计数。这启发我们,在搜索时可以只考虑数字的大小与数量,每次处理一种数字,即先预处理出每个数字出现的次数,然后在搜索时,每次考虑用几个这个数。最终的方案形如{1个1,2个3…}
class Solution {
public:
int n;
vector<vector<int>>res;
map<int,int>mp;
vector<pair<int,int>>v;
vector<int>temp;
void dfs(int step,int t)
{
//cout<<t<<endl;
if(t==0)
{
res.push_back(temp);
return ;
}
if(step==n)return ;
dfs(step+1,t);
for(int i=1;i<=v[step].second;i++)
{
if(t-i*v[step].first>=0)
{
for(int j=1;j<=i;j++)temp.push_back(v[step].first);
dfs(step+1,t-i*v[step].first);
for(int j=1;j<=i;j++)temp.pop_back();
}
}
}
vector<vector<int>> combinationSum2(vector<int>& c, int t) {
vector<int>temp;
sort(c.begin(),c.end());
for(int i=0;i<c.size();i++)
{
mp[c[i]]++;
}
n=mp.size();
for(auto i:mp)v.push_back({i.first,i.second});
//for(auto i:v)cout<<i.first<<" "<<i.second<<endl;
dfs(0,t);
return res;
}
};