- you are given an integer array nums of 2 * n integers. You need to partition nums into two arrays of length n to minimize the absolute difference of the sums of the arrays. To partition nums, put each element of nums into one of the two arrays.Return the minimum possible absolute difference.
- 引入概念:二分搜索,将搜索空间一分为二,可以显著降低复杂度。
- 将nums数组分成前半部分和后半部分,每一部分分别有n个元素.在每一部分中分别搜索可能的差值。
- 使用列表对象数组left。left[i]记录在nums数组的前半部分取i个元素放入array1时(于是其余的n - i个元素放入array2),在前半部分的意义下array1和array2的差值。
- 使用列表对象数组right,执行和列表对象数组left完全一致的操作;
- 取i个元素可以使用二进制模拟的方式实现。
- 合并:对于列表对象数组left的每一个i值,必须在right[n - i]中搜索结果。选取两者元素之和绝对值最小的元素即可。
- 方式是排序+双指针法。
AC代码如下:
class Solution {
public int minimumDifference(int[] nums) {
//保存左侧,当arr1的长度为i时,arr1和arr2的可能的差值列表
List<Integer>[] left = new List[nums.length/2 + 1];
//保存右侧,当arr1的长度为i时,arr1和arr2的可能的差值列表
List<Integer>[] right = new List[nums.length/2 + 1];
for(int i = 0;i<left.length;i++) {
left[i] = new ArrayList<>();
right[i] = new ArrayList<>();
}
//枚举每一种可能的选择
for(int i = 0;i<((1<<nums.length/2));i++)
{
int sum = 0;
int sum_1 = 0;
int cout = 0; //选择中位于数组1的个数
for(int j = 0;j<nums.length / 2;j++)
{
if(((i >> j) & 1 )== 1) //表明被选择到第一个数组中了
{
cout+=1;
sum_1+=nums[j + nums.length/2];
sum += nums[j];
}
else
{
sum_1-=nums[j+nums.length/2];
sum -= nums[j];
}
}
left[cout].add(sum);
right[cout].add(sum_1);
}
//所有差值已经计算完毕
int ans = Integer.MAX_VALUE;
for(int i = 0;i<nums.length / 2;i++)
{
left[i].sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
});
right[nums.length/2 - i].sort(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
});
int j = 0;
int k = right[nums.length / 2 - i].size() - 1;
while(k>=0 && j<left[i].size())
{
ans = Math.min(ans,Math.abs(left[i].get(j) + right[nums.length/2 - i].get(k)));
if(ans == 0)
return ans;
if(left[i].get(j) + right[nums.length/2 - i].get(k) > 0)
k--;
else j++;
}
}
return ans;
}
}