1658. 将 x 减到 0 的最小操作数
给你一个整数数组 nums
和一个整数 x
。每一次操作时,你应当移除数组 nums
最左边或最右边的元素,然后从 x
中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。
如果可以将 x
恰好 减到 0
,返回 最小操作数 ;否则,返回 -1
。
示例 1:
输入:nums = [1,1,4,2,3], x = 5 输出:2 解释:最佳解决方案是移除后两个元素,将 x 减到 0 。
示例 2:
输入:nums = [5,6,7,8,9], x = 4 输出:-1
示例 3:
输入:nums = [3,2,20,1,1,3], x = 10 输出:5 解释:最佳解决方案是移除后三个元素和前两个元素(总共 5 次操作),将 x 减到 0 。
提示:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^4
1 <= x <= 10^9
此题虽然是求最小操作数,但是可以逆向思考:
把问题转换成从 nums 中移除一个最长的子数组,使得剩余元素的和为 x。
换句话说,要从 nums 中找最长的子数组,其元素和等于 s−x,这里 s 为 nums 所有元素之和。
其实求的是最长满足和为s-x的子序列,最后的最小操作数为nums的长度减去最长子序列
1 class Solution { 2 public int minOperations(int[] nums, int x) { 3 int sum = Arrays.stream(nums).sum(); 4 int target = sum - x; 5 if (target < 0) 6 return -1; 7 int left = 0, right = 0; 8 int subSum = 0; 9 int n = nums.length; 10 int maxLen = -1; 11 while (right < n) { 12 int r = nums[right]; 13 right++; 14 subSum += r; 15 //逆向思维,寻找最长 16 while (subSum > target) { 17 int l = nums[left]; 18 left++; 19 subSum -= l; 20 } 21 //满足条件,收集结果 22 if (subSum == target) { 23 maxLen = Math.max(maxLen, right - left); 24 } 25 } 26 return maxLen == -1 ? -1 : n - maxLen; 27 } 28 }
我偏要勉强!