https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/
题目描述
给你一个整数数组 nums
和一个整数 x
。每一次操作时,你应当移除数组 nums
最左边或最右边的元素,然后从 x
中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。
如果可以将 x
恰好 减到 0
,返回 最小操作数 ;否则,返回 -1
。
示例 1:
输入:nums = [1,1,4,2,3], x = 5 输出:2 解释:最佳解决方案是移除后两个元素,将 x 减到 0 。
解题思路
这道题的意思是在数组的左右两边取元素,看取出的元素之后是否等于x,左右两边具体取几个数都不知道,这就导致非常难了。
我们可以换一种思路,题目是要取的是数组的两端,那么剩下的就是数组的中间连续部分,我们可以找中间部分的最大长度,进而求出数组两边的长度之和
我们假设数组的总和是sum,那么中间的数组之和大于等于sum-x时,可以看做是一种情况
也就是转换成了求子数组之和大于 sum-x 的最长子数组
1.定义left,right 初始都为0,sum为整个数组之和,target为子数组要大于的数 sum-x
2.当right小于数组长度时,right向右移动,直到 left 到 right 的子数组之和大于 target 时停止,然后子数组之和 tmp 减去 nums[left] ,left 向右移动,然后看 tmp 是否等于 target,如果等于,则将len更新,直到 tmp < target ,最后 right 向右移动,重复第一步;
如果left移动时,tmp正好等于target,更新当前的 len = right -left
3.直到 right == 数组的长度,最后返回数组的长度 - len
代码
public int minOperations(int[] nums, int x) {
int n = nums.length;
int left = 0,right = 0;
int sum = 0;
for(int a:nums){ //求和
sum +=a;
}
int target = sum-x;
if (target<0){ //当整个数组之和小于x时,直接返回
return -1;
}
int tmp = 0;
int len = -1;
while (right<n){
tmp+=nums[right];
right++;
while (tmp>target){
tmp-=nums[left];
left++;
}
if (tmp==target){
len = Math.max(len,right-left);
}
}
if (len == -1){//当没有满足的子数组时
return -1;
}
return nums.length-len;
}