题意:从一个数组找出一个子集,使得子集的和给定的目标最相近。
题解:数组的长度为40,找出全部子集一共有240种可能性,如果把一个数组平均分成两部分,分别算出两部分的所有子集和,每部分有220种可能,
然后再二分查找答案。
遇到这种在数组里找所有子集和,
class Solution {
public:
map<int, int> m;
int sum[1000005];
int sum2[1000005];
int p;
void fun(int n, int i, int s,vector<int>& nums, int* sum)
{
if (m[s] == 0)
{
m[s] = 1;
sum[p++] = s;
}
for (int j = i + 1; j < n; j++)
{
fun(n, j, s+nums[j], nums, sum);
}
}
int minAbsDifference(vector<int>& nums, int goal)
{
int ans = INT_MAX;
int n = nums.size()/2;
p = 0;
for (int i = 0; i < n; i++)
{
fun(n, i, nums[i], nums, sum);
}
int p1 = p;
m.clear();
for (int i = 0; i < p1; i++)
{
ans = min(ans, abs(sum[i] - goal));
}
p = 0;
for (int i = n; i < nums.size(); i++)
{
fun(nums.size(), i, nums[i],nums, sum2);
}
for (int i = 0; i < p; i++)
{
ans = min(ans, abs(sum2[i] - goal));
}
sort(sum, sum + p1);
// 1 2 5 6
for (int i = 0; i < p; i++)
{
int x = sum2[i];
int l = 0;
int r = p1;
while (l <= r)
{
int mid = (l + r) / 2;
ans = min(ans, abs(sum[mid] + x - goal));
if (sum[mid] + x > goal)
{
r = mid - 1;
}
else if (sum[mid] + x < goal)
{
l = mid + 1;
}
else
{
return 0;
}
}
}
return ans;
}
};