
总结
我觉得这个题目会的人会觉得很简单,不会的人会觉得很难,关键在于有没有想到反向思维,当正面思考考虑的情况有很多的时候我们需要进行反向思考
我最开始就是正向思考的,没有做出来这个题。
正向思考
-
定义左右指针进行遍历的时候,当此时的x不满足情况后如何修改这个指针
- 这一步也就是回退,我们需要考虑如何将这个指针进行回退
比如说当执行了x-=nums[right]后,发现x<0了,我们要回退,x+=nums[right],然后让x-=nums[left]。 - 回退的过程有一个点很难处理,就是我们如何判断回退的是左边还是右边。
- 还有一个问题就是回退的时候边界很难处理,容易越界
- 这一步也就是回退,我们需要考虑如何将这个指针进行回退
后来本来想看题解了,觉得自己做不出来了,我突然发现leecode竟然还有提示

提示是,反向思考以下,与其用前缀和后缀,可以考虑去找这个最大子数组
然后就想明白了
反向思维思路
- 先对数组求和,然后数组和-x得到了一个数y
- 此时我们就需要找这个数组中内部最长的数组=y的情况,就将这个题转换为了一个滑动窗口找最长子数组的问题。
- 之后就简单了
代码如下
java
public int minOperations(int[] nums, int x) {
int len = nums.length;
int left = 0,min=100001,sum=0;
for(int a:nums){
sum+=a;
}
int y= sum-x;//找出其中和为y的最大子数组,其余的就是这个x和y了
if(y<0){
return -1;
}
sum = 0;
for(int right = 0;right<len;right++){
sum+=nums[right];
while(sum>y){
sum-=nums[left];
left++;
}
if(sum==y){
min= Math.min(min,len-(right-left+1));
}
}
return min==100001?-1:min;
}
灵神的思路
思路1,反向思维,滑动窗口
灵神的思路和我的类似,唯一区别在于它是直接算的数组的最大长度,然后得出的最小结果,我是直接算的最小的结果
思路2,直接双指针
这个思路有点奇特,他是先找出了最长后缀,对right指针进行了移动,然后不断遍历left指针,当left指针不满足条件的时候,只去修改右侧指针即可,相比我的想法,不满足条件之后对左右指针进行判断进行修改,这个地方只对这个right进行了修改
java
class Solution {
public int minOperations(int[] nums, int x) {
int n = nums.length;
int sum = 0;
int right = n;
while (right > 0 && sum + nums[right - 1] <= x) { // 计算最长后缀
right--;
sum += nums[right];
}
if (right == 0 && sum < x) {
return -1; // 全部移除也无法满足要求
}
int ans = sum == x ? n - right : n + 1;
for (int left = 0; left < n; left++) {
sum += nums[left];
while (right < n && sum > x) {
sum -= nums[right];
right++; // 缩小后缀长度
}
if (sum > x) {
break; // 缩小失败,说明前缀过长
}
if (sum == x) {
ans = Math.min(ans, left + 1 + n - right); // 前缀+后缀长度
}
}
return ans > n ? -1 : ans;
}
}
作者:灵茶山艾府
链接:https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/solutions/2048811/ni-xiang-si-wei-pythonjavacgo-by-endless-b4jt/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。