算法入门:专题攻克二---滑动窗口(将x减到0的最小操作数,更新中。。。)
🎬 胖咕噜的稞达鸭:个人主页

将 x 减到 0 的最小操作数
1658. 将 x 减到 0 的最小操作数

- 题目解析:
在整数数组nums中,每当移除数组最左边或者最右边的元素,就要从x中减去该元素的值,将x减到0,并且返回最小的操作数字,也就是从原数组中移除了多少个数字可以将x减到0,移除的数字越少就返回,改动原数组改动最小的返回。
给一个例子:nums=[ 1 , 1 , 4 , 2 , 3 ] ,此时x=5,移除数组索引为0的元素1,x-1=4,x现在还没被减到0,移除前两个元素和最后一个元素,x=0,此时改动了3个元素,返回3;还可以移除后两个元素,x = 0,此时只改动了两个元素,返回2.题目要求要返回最小的操作数,此时返回2.
如果数组中找不到可以使得x减到0的(如数组:nums = [ 5 , 6 , 7 , 8 , 9 ],返回-1即可。
- 算法原理:
同一个数组,操作数最小,x减去的数字越少就满足题目的要求,x中减去的数字越少也就意味着留下来的数字越多,也就是说最后比较的是,返回ret,ret的最大值即可。可以将所有数字都相加,最终结果放到sum中,如果所有元素的和等于sum-x,就可以计算此时最长的子数组的长度len.
可以先用暴力枚举的方法,用双指针left,right从数组索引为0的位置开始遍历,right从数组索引为0的位置开始向后,每遍历一个数字加到Add中。当Add大于sum-x的时候,意味着left该出窗口了,如果Add等于sum-x的时候,就是我们想要的结果,将ret更新,从更新前的ret到right-left+1的ret选取大的进行更新。最后返回的是数组的元素个数减去ret,本身要求的就是返回操作的最小数字。ret中的数字越多,操作的数字就越少。
还有一种情况:如果数组中找不到可以将x减为0的组合,返回-1.此时可以先将ret置为-1,初始化的时候置为-1,等到数组中有可以将x减为0的组合,再更新ret,这也是一个小细节。
- 现在来写代码。
第一步:
将数组中所有数字相加sum,我们要找的组合一定是等于sum-x ;
第二步:初始化ret,如果数组中没有组合可以将x减为0,返回-1;有就执行下面的操作;
第三步:定义双指针,进入窗口(当right一个一个遍历加到Add中,Add<sum-x);出窗口(当Add > sum-x,此时left需要向后移动一个位置,表示出窗口);再次判断,此时的left,right的区间内数字相加是不是Add==sum-x。如果是就更新ret,ret=right-left+1和ret(原始)的最大值。
第四步:返回。
class Solution {
public:int minOperations(vector<int>& nums, int x) {int sum=0;for(int a:nums) sum+=a;int target=sum-x;if(target<0) return -1;int ret=-1;for(int left=0,right=0,Add=0;right<nums.size();right++){Add+=nums[right];while(Add>target) {Add -= nums[left++]; }if(Add == target) {ret =max(ret,right-left+1);}}if(ret == -1)return ret=-1;else {return nums.size()-ret;}}
};
