此题查看范围,不能使用动态规划
而观察发现,数组长度很小,因此使用二分
static class Solution {
//使用二分
public int minAbsDifference(int[] nums, int goal) {
int N = nums.length;
int M = N >> 1;
ArrayList<Integer> leftNums = new ArrayList<>();
ArrayList<Integer> rightNums = new ArrayList<>();
generateAllNums(leftNums, 0, M, nums, 0);
// System.out.println(leftNums.size());
// for (Integer leftNum : leftNums) {
// System.out.print(leftNum + " ");
// }
// System.out.println();
generateAllNums(rightNums, M, N, nums, 0);
// System.out.println(rightNums.size());
// for (Integer rightNum : rightNums) {
// System.out.print(rightNum + " ");
// }
// System.out.println();
//左边排序
Collections.sort(leftNums);
//右侧排序
Collections.sort(rightNums);
//在左侧找接近goal的最大值
int leftNear = binarySearchNearGoal(0, leftNums.size() - 1, leftNums, goal);
//System.out.println("left: " + leftNear);
if (leftNear == goal)
return 0;
//在右侧找接近goal的最大值
int rightNear = binarySearchNearGoal(0, rightNums.size() - 1, rightNums, goal);
//System.out.println("right: " + rightNear);
if (rightNear == goal)
return 0;
//两边同时找
int near = Math.abs(leftNear - goal) <= Math.abs(rightNear - goal) ? leftNear : rightNear;
for (Integer leftNum : leftNums) {
int allNear = binarySearchNearGoal(0, rightNums.size() - 1, rightNums, goal - leftNum);
if (allNear + leftNum == goal)
return 0;
near = Math.abs(allNear + leftNum - goal) <= Math.abs(near - goal) ? allNear + leftNum : near;
//System.out.println(near);
}
return Math.abs(near - goal);
}
private void generateAllNums(ArrayList<Integer> res, int index, int maxLen, int[] nums, int total) {
if (index >= maxLen) {
res.add(total);
return;
}
//用
generateAllNums(res, index + 1, maxLen, nums, total + nums[index]);
//不用
generateAllNums(res, index + 1, maxLen, nums, total);
}
private int binarySearchNearGoal(int i, int j, ArrayList<Integer> nums, int goal) {
int left = i;
int right = j;
while (left <= right) {
int mid = left + ((right - left) >> 1);
if (nums.get(mid) > goal) {
right = mid - 1;
} else if (nums.get(mid) == goal) {
return nums.get(mid);
} else {
left = mid + 1;
}
}
left = left > j ? j : left;
right = right < 0 ? 0 : right;
int rightNear = nums.get(right);
int leftNear = nums.get(left);
return Math.abs(goal - rightNear) <= Math.abs(goal - leftNear) ? rightNear : leftNear;
}
}