1755. 最接近目标值的子序列和
给你一个整数数组 nums 和一个目标值 goal 。
你需要从 nums 中选出一个子序列,使子序列元素总和最接近 goal 。也就是说,如果子序列元素和为 sum ,你需要 最小化绝对差 abs(sum - goal) 。
返回 abs(sum - goal) 可能的 最小值 。
注意,数组的子序列是通过移除原始数组中的某些元素(可能全部或无)而形成的数组。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/closest-subsequence-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
import java.util.Arrays;
class Solution {
public int minAbsDifference(int[] nums, int goal) {
int half = nums.length >> 1;
int[] f1 = new int[1 << half], f2 = new int[1 << (nums.length - half)];
for (int i = 1; i < f1.length; ++i) { //前半部分所有组合
f1[i] = f1[i - Integer.lowestOneBit(i)] + nums[Integer.numberOfTrailingZeros(i)];
// for (int j = 0; j < half; ++j) {
// if ((i & (1 << j)) != 0) {
// /**
// * 常规写法,累加选中的每个数
// */
//// f1[i] += nums[j];
// /**
// * 动态规划
// * 借助之前的累加和
// */
// f1[i] = f1[i ^ (1 << j)] + nums[j];
// break;
// }
// }
}
for (int i = 1; i < f2.length; ++i) { //后半部分所有组合
f2[i] = f2[i - Integer.lowestOneBit(i)] + nums[half + Integer.numberOfTrailingZeros(i)];
// for (int j = 0; j < nums.length - half; ++j) {
// if ((i & (1 << j)) != 0) {
//// f2[i] += nums[half + j];
// f2[i] = f2[i ^ (1 << j)] + nums[half + j];
// break;
// }
// }
}
/**
* 解法一:
* 二分查找
* 时间复杂度
* n * (2^ n)
*/
// Arrays.sort(f2);
// int ans = Integer.MAX_VALUE;
// for (int i = 0; i < f1.length; ++i) { //枚举f1
// int target = goal - f1[i];
// int index = search(f2, target); //二分查找f2
// if (index < f2.length) {
// ans = min(ans, abs(f1[i] + f2[index] - goal));
// }
// if (index - 1 >= 0) {
// ans = min(ans, abs(f1[i] + f2[index - 1] - goal));
// }
// }
/**
* 解法二:
* 双指针
* 时间复杂度
* 2 ^ n
*/
Arrays.sort(f1);
Arrays.sort(f2);
int ans = Integer.MAX_VALUE;
int left = 0, right = f2.length - 1;
while (left < f1.length && right >= 0) {
int sum = f1[left] + f2[right];
ans = Math.min(ans, Math.abs(sum - goal));
if (sum == goal) {
/**
* 若0可以,则0一定是最优解
*/
break;
} else if (sum > goal) {
right--;
} else {
left++;
}
}
return ans;
}
}
心之所向,素履以往 生如逆旅,一苇以航

浙公网安备 33010602011771号