题目地址:
给定一个长 2 n 2n 2n的数组 A A A,要求将其分为两部分,使得两部分各自和作差的绝对值最小,返回这个最小的绝对值。
先开个哈希表 m m m存 A A A的后 n n n个数字的所有组合的和,key是数字个数,value是和的所有可能性,然后再暴力枚举前 n n n个数字的所有组合,如果这个组合含 c c c个数字,那么后 n n n个数,就要取 n − c n-c n−c个数字,为了二分方便,哈希表的value用set来存;如果前 n n n个数字的某个组合的和是 s s s,那么我们就要求 m [ n − c ] m[n-c] m[n−c]里与 s s s求和之后离 ∑ A / 2 \sum A/2 ∑A/2最近的数,这个可以用lower_bound来做。代码如下:
class Solution {
public:
int minimumDifference(vector<int> &a) {
int n = a.size() / 2, res = INT_MAX;
unordered_map<int, set<long>> mp;
dfs(n, 0, 0, a, mp);
long sum = 0;
for (int x : a) sum += x;
for (int i = 0; i < 1 << n; i++) {
int cnt = 0;
long s = 0;
for (int k = 0, t = i; t; k++) {
if (t & 1) {
s += a[k];
cnt++;
}
t >>= 1;
}
auto &st = mp[n - cnt];
auto it = st.lower_bound(sum / 2 - s);
if (it != st.end()) res = min(res, (int)abs(sum - 2 * (*it + s)));
if (it != st.begin()) res = min(res, (int)abs(sum - 2 * (*(--it) + s)));
}
return res;
}
void dfs(int u, int cnt, int sum, vector<int> &a,
unordered_map<int, set<long>> &mp) {
mp[cnt].insert(sum);
for (int i = u; i < a.size(); i++) dfs(i + 1, cnt + 1, sum + a[i], a, mp);
}
};
时间复杂度 O ( 2 n log n ) O(2^n\log n) O(2nlogn),空间 O ( 2 n ) O(2^n) O(2n)。