将 x 减到 0 的最小操作数 -- 滑动窗口

给你一个整数数组 n u m s nums nums和一个整数 x x x 。每一次操作时,你应当移除数组 n u m s nums nums 最左边或最右边的元素,然后从 x x x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。

如果可以将 x x x 恰好减到 0 0 0 ,返回最小操作数 ;否则,返回 − 1 -1 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 <= 105
1 <= nums[i] <= 104
1 <= x <= 109

  题目即是要求最少的来自前端和后端的数,使得它们的和等于 x x x。因此,也就是求数组 n u m s nums nums中最长的连续子序列的和等于 ∑ i = 0 n n u m s [ i ] − x \sum_{i=0}^{n}nums[i]-x i=0nnums[i]x
  思路:滑动窗口。初始时子序列的首尾均在第一个元素上,子序列成都为0;每次循环从子序列右侧的第一个元素加入子序列,并计算已加入子序列的和 c u r r e n t _ s u m current\_sum current_sum。如果 c u r r e n t _ s u m > ∑ i = 0 n n u m s [ i ] − x current\_sum>\sum_{i=0}^{n}nums[i]-x current_sum>i=0nnums[i]x,则说明右侧加入的数过大,从子序列的最左侧删除元素直到 c u r r e n t _ s u m ≤ ∑ i = 0 n n u m s [ i ] − x current\_sum\leq \sum_{i=0}^{n}nums[i]-x current_sumi=0nnums[i]x为止。如果此时刚好有 c u r r e n t _ s u m = ∑ i = 0 n n u m s [ i ] − x current\_sum= \sum_{i=0}^{n}nums[i]-x current_sum=i=0nnums[i]x,若此子序列的长度比记录过的最长子序列长度要长,则更新最长子序列长度为该子序列长度,否则保持不变。如果此时子序列右侧已经达到序列最右端,则说明过程已结束,退出循环。

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int l = 0, r = 0;
        int len = nums.size();
        int sum = 0, curr = 0;
        int Maxmid = -1;
        for(int i = 0; i < len; ++i){
            sum += nums[i];
        }
        while(l < len){
            if(r < len){
                curr += nums[r];
                ++r;
            }
            while(curr > sum - x && l < len){
                curr -=nums[l];
                ++l;
            }
            if(curr == sum - x){
                Maxmid = (r - l > Maxmid) ? r - l : Maxmid;
            }

            if(r == len)
                break;
        }
        
        return (Maxmid == -1) ? -1 : len - Maxmid;
    }
};

你可能感兴趣的:(LeetCode,leetcode)