将数组分成两个数组并最小化数组和的差(折半搜索+二分)
2 n ≤ 30 2n\le 30 2n≤30,显然是折半搜索。
预处理前一半和后一半的选正的差值。
然后排序去重。
最后扫一遍,枚举正号的个数: i ∈ [ 0 , n ] i\in[0,n] i∈[0,n]。
前一半正号选了个 i i i个,那么后一半正号也要选 i i i个,这里两者个数才会相等。
然后二分找到最近的两个数。
class Solution {
vector<int> s[16],t[16];
int o[32768];
public:
int minimumDifference(vector<int>& nums) {
int n=nums.size()>>1,i,j,k,ans=1000000000;
for(i=0;i<=n;i++)
{
s[i].clear();
t[i].clear();
}
int st=1<<n;
for(i=0;i<st;i++)
{
if(i)o[i]=o[i>>1]+(i&1); //二进制1的个数.
else o[i]=0;
for(j=k=0;j<n;j++)if(i>>j&1)k+=nums[j];
else k-=nums[j];
s[o[i]].push_back(k);
for(j=k=0;j<n;j++)if(i>>j&1)k+=nums[j+n];
else k-=nums[j+n];
t[o[i]].push_back(k);
}
for(i=0;i<=n;i++)
{
sort(t[i].begin(),t[i].end());
t[i].erase(unique(t[i].begin(),t[i].end()),t[i].end());//去重
}
for(i=0;i<=n;i++)for(auto &c:s[i])
{
auto it=lower_bound(t[i].begin(),t[i].end(),c);
if(it!=t[i].end())ans=min(ans,*it-c);
if(it!=t[i].begin())
{
it--;
ans=min(ans,c-*it);
}
}
return ans;
}
};