将数组分成两个数组并最小化数组和的差(折半搜索+二分)

2 n ≤ 30 2n\le 30 2n30,显然是折半搜索。

预处理前一半和后一半的选正的差值。

然后排序去重。

最后扫一遍,枚举正号的个数: 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;
    }
};