题目:脑客爱刷题
给定一个全是正数的数组arr,定义一下arr的最小不可组成和的概念:
1,arr的所有非空子集中,把每个子集内的所有元素加起来会出现很多的值,其中最小的记为min,最大的记为max;
2,在区间[min,max]上,如果有一些正数不可以被arr某一个子集相加得到,那么这些正数中最小的那个,就是arr的最小不可组成和;
3,在区间[min,max]上,如果所有的数都可以被arr的某一个子集相加得到,那么max+1是arr的最小不可组成和;
请写函数返回arr的最小不可组成和。
struct pair_hash
{
int operator()(const pair<int,int> &a)const
{
return hash<int>()(a.first)+hash<int>()(a.second);
}
};
void getFirstUnFormedNum_core(const int* num,const int length,const int index,const int presum,unordered_set<int> &sumset,unordered_set<pair<int,int>,pair_hash> &Iscompute)
{
pair<int,int> tmp=make_pair(index,presum);
if(Iscompute.find(tmp)!=Iscompute.end())
return;
if(index==length)
sumset.emplace(presum);
else
{
getFirstUnFormedNum_core(num,length,index+1,presum,sumset,Iscompute);
getFirstUnFormedNum_core(num,length,index+1,presum+num[index],sumset,Iscompute);
}
Iscompute.emplace(tmp);
}
int getFirstUnFormedNum(const int* num,const int length)
{
if(num==nullptr || length<=0)
return -1;
unordered_set<int> sumset;
unordered_set<pair<int,int>,pair_hash> Iscompute;
getFirstUnFormedNum_core(num,length,0,0,sumset,Iscompute);
int minnum=INT_MAX;
for(int i=0;i<length;i++)
minnum=min(minnum,num[i]);
for(int i=minnum+1;i>0;i++)
{
if(sumset.find(i)==sumset.end())
return i;
}
//有可能从minnum一直到INT_MAX都不是“最小不可组成和”,所以此时返回0
return 0;
}
进阶:如果已知arr中肯定有1这个值,怎么实现能更快一些?
//本程序不考虑溢出
int getFirstUnFormedNum_With_One(vector<int> num)
{
if(num.empty())
return -1;
sort(num.begin(),num.end());
int rangeMax=num[0];
if(rangeMax!=1)
throw new exception;
for(int i=1;i<num.size();i++)
{
if(num[i]>rangeMax+1)
return rangeMax+1;
rangeMax+=num[i];
}
return rangeMax+1;
}