分析:
如果正向解答,每次减去数组最左边或者最右边的元素,来保证操作数为最优,再去判断x是否为0。某一次操作后,x的结果有三种可能,如果是等于0,那最好不过,因为一路都是选择较大值,所得操作数可以保证为最优解,如果是大于0,那就是无解,如果是小于0,这就麻烦了,需要回退到上一步重新选择,选择减去较小值,此时依然有三种情况,等于0不用说,皆大欢喜,如果大于0,那继续向后操作,如果是小于0,需要继续回退。也就是说,如果每次选择减去较大值,那么当x的值小于0时,需要回退,一旦回退的值仍然不满足条件,需要继续向后回退或者向后继续进行,而每次选择都有可能是另外两种不符合条件的情况。
而如果暴力尝试每一种组合,每一次选择都有两张情况,最左边或者最右边,一旦数组元素过多,组合数就相当于指数爆炸。
解题思路:抛开两边看中间,如果有解,无非就是数组中间的元素和为,数组元素总大小减去x,最优解就意味着,中间元素的个数要最多。也就是说,此时题目相当于是在数组中寻找值为数组元素和-x的最长子数组。而对于连续数组的求解,滑动窗口是最好的选择。
按照思路,提交代码后,出现报错。如下图
heap-buffer-overflow,堆数组越界,很明显,只有vector数组的数据是在堆上存储的,也就是vector数组出现越界访问。
开始寻找错误:
利用错误样例实验,在访问vector数组前的地方对数组下标进行打印。
不难看出越界错误是因为l在内循环中不断增加,最终越界导致的。加上对l的判断防止越界访问即可解决问题。
最终代码:
class Solution {
public:
int minOperations(vector<int>& nums, int x) {
int sum=0;
for(auto e:nums)
{
sum+=e;
}
int target=sum-x;
if(target<0) retunr -1;//优化
int maxlength=-1;
int l=0,r=0;
int sum1=0;
while(l<nums.size()&&r<nums.size())
{
sum1+=nums[r];//进窗口
while(l<nums.size()&&sum1>target)//防止l下标越界访问vector
{
sum1-=nums[l++];//出窗口
}
if(sum1==target)
{
maxlength=max(maxlength,r-l+1);//更新结果
}
r++;
}
return maxlength==-1?maxlength:(nums.size()-maxlength);
}
};