Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【Day 47 】2021-10-26 - Number of Operations to Decrement Target to Zero #64

Open
azl397985856 opened this issue Oct 25, 2021 · 153 comments

Comments

@azl397985856
Copy link
Contributor

Number of Operations to Decrement Target to Zero

入选理由

暂无

题目地址

https://binarysearch.com/problems/Number-of-Operations-to-Decrement-Target-to-Zero

前置知识

  • 二分法
  • 滑动窗口

题目描述

You are given a list of positive integers nums and an integer target. Consider an operation where we remove a number v from either the front or the back of nums and decrement target by v.

Return the minimum number of operations required to decrement target to zero. If it's not possible, return -1.

Constraints

n ≤ 100,000 where n is the length of nums
Example 1
Input
nums = [3, 1, 1, 2, 5, 1, 1]
target = 7
Output
3
Explanation
We can remove 1, 1 and 5 from the back to decrement target to zero.

Example 2
Input
nums = [2, 4]
target = 7
Output
-1
Explanation
There's no way to decrement target = 7 to zero.

@yanglr
Copy link

yanglr commented Oct 25, 2021

思路

题意: 给你一个正整数数组nums和一个整数target。每一次操作,只能从nums数组的最前面最后面删除一个数字v,同时将target减去v。

返回将target减为零所需的最少操作次数。如果不可能做到,则返回-1。

限制条件

n ≤ 100,000,其中n是nums的长度。

问题转换

题目要求删掉数组nums的左右两端的元素,并且删掉的元素和为target,也就是留下中间连续的子数组,其和为sum(nums) - target;
题目还让求出最小的操作次数,即删掉的元素个数越少越好,也就是留下的中间子数组的长度越大越好。

那么问题就转化为了找数组中间和为sum(nums) - target的最长子数组,令该表达式为我们的新目标new_target, 并将原数组的长度记作N。

使用滑动窗口

接下来就可以用滑动窗口来求和为newTarget的滑动窗口的最大长度了:

  • 如果能找到和为newTarget的滑动窗口, 并将最大长度其记作maxLen, 那么要求的最小操作次数为 N - maxLen
  • 如果不存在和为newTarget的滑动窗口, 就返回-1。

代码

实现语言: C++

int solve(vector<int>& nums, int target) {
    // 双指针
    int N = nums.size();
    int newTarget = accumulate(nums.begin(), nums.end(), 0) - target;
    if (newTarget == 0) return N;
    int curSum = 0;
    int maxLen = 0;
    int left = 0;  // left: 滑动窗口左边界, i: 滑动窗口右边界right
    for (int i = 0; i < N; i++)
    {
        curSum += nums[i];
        while (curSum >= newTarget && i >= left) // 寻找一个新的和为newTarget的滑动窗口区间
        {
            if (curSum == newTarget) // 当找到的新的和为newTarget的滑动窗口区间更长时, 更新其长度
                maxLen = max(maxLen, i - left + 1);

            curSum -= nums[left]; // 扔掉滑动窗口最左侧的数
            left++;
        }
    }
    return maxLen == 0 ? -1 : N - maxLen;
}

复杂度分析

  • 时间复杂度: O(n)
  • 空间复杂度: O(1)

@wangzehan123
Copy link

int solve(vector<int>& nums, int target) {
    if (target == 0) return 0;
    int N = nums.size(), msum = accumulate(nums.begin(), nums.end(), 0) - target, ans = INT_MAX;
    if (msum <= 0) return msum == 0 ? N : -1;

    unordered_map<int, int> m{{0, -1}};
    for (int i = 0, s = 0; i < N; i++) {
        s += nums[i];
        auto it = m.find(s - msum);
        if (it != m.end()) ans = min(ans, N - (i - it->second));
        if (!m.count(s)) m[s] = i;
    }
    return ans == INT_MAX ? -1 : ans;
}

@for123s
Copy link

for123s commented Oct 25, 2021

代码

  • 语言支持:C++

C++ Code:

int solve(vector<int>& nums, int target) {
    int sum = 0;
    for(int i=0;i<nums.size();i++)
        sum += nums[i];
    target = sum - target;
    if(target==0)
        return nums.size();
    else if(target<0)
        return -1;
    int l = 0, r = 0, max_val = 0;
    sum = 0;
    while(r<nums.size())
    {
        sum += nums[r];
        while(sum>target)
        {
            sum -= nums[l];
            l++;
        }
        if(sum==target)
            max_val = max(max_val,r - l + 1);
        r++;
    }
    if(max_val==0)
        return -1;
    return nums.size() - max_val;
}

复杂度分析

令 n 为数组长度。

  • 时间复杂度:$O(n)$
  • 空间复杂度:$O(1)$

@zhangzz2015
Copy link

zhangzz2015 commented Oct 25, 2021

思路

  • 理解题目意思花了一些时间,要找到最少的操作次数,从左边或者右边累加,等于target。[ 3 1 2 1 1 1 4] 用这个例子说明,最少的次数是2, 因为可以累加最后一个和第一个。在第一次,你可以挑选第一个或者最后一个元素,如果你选择第一个,下一次,你可以选择第二个或者最后一个。可先求出totalSum,该问题可以转化为找到一个最长的连续子数组,他的和为totalSum - target。因为都是正数,有两种方法应该都可以,第一种采用滑动窗口,第二种采用前缀和。方法1,标准的滑动窗口, 当窗口的总和少于目标值,增加右边界,如果超过目标值,增加左边界,正好等于target,更新结果,找最长的。时间复杂度为 O(N),空间复杂度为O(1)
int solve(vector<int>& nums, int target) {

   ///   [i j] --- > sum = total - target;
   if(target ==0)
     return 0;  
   int sum =0; 
   for(int i=0; i< nums.size(); i++)
   {
       sum += nums[i]; 
   }
    
   sum = sum - target; 
   if(sum<0)
     return -1; 
   int left =0; 
   int right =0; 
   int ret = -1; 
   while(right < nums.size())
   {
       sum -= nums[right]; 

       while(sum<0)
       {
           sum +=nums[left]; 
           left++; 
       }

       if(sum==0)
       {
           ret = max(ret, right - left + 1); 
       }
       right++; 
   } 

   return  ret==-1? -1 : nums.size() - ret;     
}

@Menglin-l
Copy link

通过arraySum - target将问题转化为求最长subarray


代码部分:

class Solution {
    public int solve(int[] nums, int target) {
        int t = - target;
        for (int num: nums) t += num;
        if (t == 0) return nums.length; // 此时最长subarray就是原数组
        if (t < 0) return -1;

        int left = 0, sum = 0, L = 0;
        for (int right = 0; right < nums.length; right ++) {
            sum += nums[right];
            while (sum > t) {
                sum -= nums[left ++];
            }
                if (sum == t) {
                    L = Math.max(L, right - left + 1);
                }
        }
        return L > 0 ? nums.length - L : -1;
    }
}

复杂度:

Time: O(n)

Space: O(1)

@zhangyalei1026
Copy link

思路

将问题转化为找到和为k的最长的连续数组问题。用滑动窗口模板。
注意edge case。

代码

class Solution:
    def solve(self, nums, target):
        # 中间的subarray = sum - target,且要保证这个长度最长
        # 转化成了找到和是subarray的最长的连续数组
        # 用滑动窗口的模板
        # 长度right - left + 1
        if sum(nums) < target:
            return -1
        if sum(nums) == target:
            return len(nums)
        left = 0
        subsum = sum(nums) - target
        temp = 0
        steps = 0
        for right in range(len(nums)):
            temp += nums[right]
            while temp >= subsum and left <= right:
                if subsum == temp:
                    steps = max(steps, right - left + 1)
                # 开始扔左边的元素,因为进入while loop的时候一定是temp >= subsum的时候,也就是满足条件的时候
                temp -= nums[left]
                left += 1
        return -1 if steps == 0 else len(nums) - steps

复杂度分析

时间复杂度:O(n)
空间复杂度:O(1)

@yachtcoder
Copy link

Convert to a sliding window problem.
O(n), O(1)

class Solution:
    def solve(self, nums, target):
        ss = sum(nums)
        if target == 0: return 0
        if ss < target: return -1
        if ss == target: return len(nums)
        target = ss - target
        #max sliding window sum to target
        l = 0
        ret = -1
        ss = 0
        for r in range(len(nums)):
            n = nums[r]
            ss += n
            while ss > target and r > l:
                ss -= nums[l]
                l += 1
            if ss == target:
                ret = max(ret, r - l + 1)
        return len(nums) - ret if ret > 0 else -1

@JiangyanLiNEU
Copy link

Sliding Window

  • find the longest subarray that sum up to sum(nums)-target
  • Runtime = O(n), Space = O(1)

JavaScript Code

class Solution {
    solve(nums, target) {
        // Get the sum of array
        let sum = 0;
        for (let num of nums){
            sum+= num;
        };
        // Edge cases
        if (sum<target){
            return -1;
        }else if (sum===target){
            return nums.length;
        }
        // target sum of window
        let targetSum = sum-target;
        // sliding window to find the longest sub array
          // find the starting left point
        let left = 0;
        while (nums[left]>targetSum){
            left++;
            if (left==nums.length){
                return -1
            };
        };
        let right = left;
        let curSum = nums[left];
        let result = Math.pow(10, 1000);
          // move the window
        while (right<nums.length){
            if (curSum == targetSum){
                result = result>nums.length-(right-left+1) ? nums.length-(right-left+1) : result;
                curSum -= nums[left];
                left++;
            }else if (curSum > targetSum){
                curSum -= nums[left];
                left++;
            }else if(curSum < targetSum){
                right++;
                if (right==nums.length){
                    return result == Math.pow(10, 1000) ? -1 : result;
                }else{
                    curSum += nums[right];
                };
            if (left>right){
                right = left;
                if (right==nums.length){
                    return -1;
                }else{
                    curSum += nums[right];
                };
            };
            };
        };
    }
}

Python Code

class Solution:
    def solve(self, nums, target):
        summ = sum(nums)
        length = len(nums)
        if summ < target:
            return -1
        if summ == target:
            return len(nums)
        inSum = summ-target
        left = 0
        result = float('inf')
        while nums[left] > inSum:
            left += 1
            if left == length:
                return -1
        right = left
        cur =  nums[left]
        while right<length:
            if cur == inSum:
                result = min(result, length-(right-left+1))
                left += 1
                cur -= nums[left-1]
            elif cur > inSum:
                left += 1
                cur -= nums[left-1]
            elif cur < inSum:
                right += 1
                if right == length:
                    return -1 if result == float('inf') else result
                cur += nums[right]

@ZacheryCao
Copy link

Idea:

Sliding widow. The longest window whose value is sum(nums) - target

Code:

class Solution:
    def solve(self, nums, x):
        if not x:
            return 0
        if not nums or nums[0] > x and nums[-1] > x :
            return -1
        n = sum(nums)
        k = n - x
        if n < x:
            return -1
        l ,r, cur = 0, 0, 0
        ans = math.inf
        while r < len(nums):
            cur += nums[r]
            while cur > k:
                cur -= nums[l]
                l += 1
            if cur == k:
                ans = min(ans, len(nums) - (r - l + 1))
            r += 1
        return ans if ans != math.inf else -1

Complexity:

Time: O(N)
Space: O(1)

@mixtureve
Copy link

mixtureve commented Oct 25, 2021

思路

滑动窗口. 一定要注意 edge cases

代码

  • 语言支持:Java

Java Code:

class Solution {
    public int solve(int[] nums, int target) {
        int sum = Arrays.stream(nums).sum();
        if (sum - target < 0) { 
            return -1; 
        }
        if (sum - target == 0) {
            return nums.length;
        }
        int ret = longestSubarraySumEqualsK(nums, sum - target);
        return ret == -1? ret: nums.length - longestSubarraySumEqualsK(nums, sum - target);
    }


    public int longestSubarraySumEqualsK(int[] nums, int k) {
        int slow = 0;
        int curSum = 0;
        int maxLen = 0;
        for (int fast = 0; fast < nums.length; fast++) {
            curSum += nums[fast];
            while (slow <= fast && curSum > k) {
                curSum -= nums[slow++];
            }
            if (curSum == k) {
                if (fast - slow + 1 > maxLen) {
                    maxLen = fast - slow + 1;
                } 
            }
        }
        return maxLen == 0? -1: maxLen;  // 注意 handle 不可能的情况
    }
}

复杂度分析

令 n 为数组长度。

  • 时间复杂度:$O(n)$
  • 空间复杂度:$O(n)$

@Daniel-Zheng
Copy link

思路

滑动窗口。

代码(C++)

int solve(vector<int>& nums, int target) {
    int sum = 0, res = -1, left = 0, right = 0, curSum = 0;
    for(int i = 0; i < nums.size(); i++) sum += nums[i];
    int tar = sum - target;
    if (tar == 0) return nums.size();
    while (right < nums.size()) {
        curSum += nums[right];
        while (curSum >= tar) {
            if (curSum == tar) res = max(res, right - left + 1);
            curSum -= nums[left++];
        }
        right++;
    }
    return res == -1 ? -1 : nums.size() - res;
}

复杂度分析

  • 时间复杂度:O(N)
  • 空间复杂度:O(1)

@james20141606
Copy link

Day 47: 843. Number of Operations to Decrement Target to Zero (sliding window)

  • Problem Link

  • Ideas

    • We use sliding window, convert the problem to: find the maximum subarray which sums to sum(nums) - target. Should be careful about the edge cases
  • Complexity: hash table and bucket

    • Time: O(N)
    • Space: O(1)
  • Code

class Solution:
    def solve(self, A, target):
        if not A and not target: return 0
        target = sum(A) - target
        ans = len(A) + 1
        i = t = 0

        for j in range(len(A)):
            t += A[j]
            while i <= j and t > target:
                t -= A[i]
                i += 1
            if t == target: ans = min(ans, len(A) - (j - i + 1))
        return -1 if ans == len(A) + 1 else ans

#transform this problem to: find the maximum subarray which sums to sum(nums) - target
class Solution:
    def solve(self, nums, target):
        #if target == 0: return 0
        #if sum(nums) < target: return -1
        if sum(nums) == target: return len(nums)
        sum_remain = sum(nums) - target
        max_len = 0
        left = 0
        cur_sum = 0
        for right, num in enumerate(nums):
            cur_sum += num
            while cur_sum > sum_remain and left <= right:  #if we add this left <= right, the first two if could be removed!
                cur_sum -= nums[left]
                left += 1
            if cur_sum == sum_remain:
                max_len = max(max_len, right - left + 1)
        print (max_len)    
        return len(nums) - max_len if max_len != 0 else -1 #max_len = 0 or not could not distinguish [2,2] 3 and [1] 1, have to add several conditions at the beginning

@cicihou
Copy link

cicihou commented Oct 25, 2021

class Solution:
    def solve(self, nums, target):
        target = sum(nums) - target
        if target == 0:
            return len(nums)
        elif target < 0:
            return -1

        l = total = res = 0
        for r in range(len(nums)):
            total += nums[r]
            while total > target:
                total -= nums[l]
                l += 1
            if total == target:
                res = max(res, r-l+1)
        return len(nums) - res if res > 0 else -1

@florenzliu
Copy link

Explanation

  • the minimum number of operations to reach target = the maximum length of sublist that equals to sum(nums) - target
  • use sliding window to get the current sum
    • if equal, update the maximum length
    • if larger than sum(nums)-target, reduce window size by moving left pointer forward
  • finally return len(nums) - maxLength

Python

class Solution:
    def solve(self, nums, target):
        s = sum(nums)
        if s == target: 
            return len(nums)
        elif s < target:
            return -1
        else:
            maxLength = 0
            newTarget = sum(nums) - target
            left, currSum = 0, 0
            for i in range(len(nums)):
                currSum += nums[i]
                while currSum > newTarget:
                    currSum -= nums[left]
                    left += 1
                if currSum == newTarget:
                    maxLength = max(maxLength, i-left+1)
            return len(nums)-maxLength if maxLength != 0 else -1

Complexity:

  • Time Complexity: O(N)
  • Space Complexity: O(1)

@heyqz
Copy link

heyqz commented Oct 25, 2021

class Solution:
    def solve(self, nums, target):
        if not nums and not target:
            return 0
        n = len(nums)
        target = sum(nums) - target
        ans = float('inf')
        i = total = 0

        for j in range(n):
            total += nums[j]
            while i <= j and total > target:
                total -= nums[i]
                i += 1
            if target == total:
                ans = min(ans, n - (j - i + 1))

        return -1 if ans == float('inf') else ans

time complexity: O(n)
space complexity: O(1)

@shixinlovey1314
Copy link

Title:Number of Operations to Decrement Target to Zero

Question Reference LeetCode

Solution

Let's say the after adding up all the items in the array, the total is sum.
We are actually try to find the size of the largest sub array, which sum - sum(sub_array) = target => sum(sub_array) = sum - target.
Then answer would be array.size() - sub_array.size().

To find the largest sub-array, we use a map, the key is the cumulative sum so far, and the value is the index for the cumulative sum.
Note, since we want to find the largest sub-array, when we encounter the same cumulative sum, we DO NOT update the value.

Each time we got a new cumulative sum for current index i, sum(i), we try to see if sum(i) - sum(sub_array) is in the map, if so, we have found a candidate.

Code

int solve(vector<int>& nums, int target) {
    if (!target)
        return 0;
    
    int total = 0;
    int len = 0;
    for (int num : nums) {
        total += num;
    }

    int tar = total - target;
    if (!tar)
        return nums.size();

    unordered_map<int, int> data_store;
    data_store[0] = -1;
    int cur = 0;

    for (int i = 0; i < nums.size(); i++) {
        cur += nums[i];

        if (!data_store.count(cur)) {
            data_store[cur] = i;
        }

        if (data_store.count(cur - tar) && (i - data_store[cur - tar]) > len) {
            len = i - data_store[cur - tar];
        }
    }

    return len? nums.size() - len : -1;
}

Complexity

Time Complexity and Explanation

O(n), we visit each item in the array twice

Space Complexity and Explanation

O(n), we need to use map to store the cumulative sum and its index

@Maschinist-LZY
Copy link

思路

官方题解思路,转化问题,滑动窗口(思路真的学习到了)

代码

  • 语言支持:C++

C++ Code:

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int newTarget = 0;
        int sum = 0;
        for(auto e:nums){
            sum += e;
        }
        newTarget = sum - x;
        if(newTarget == 0)return nums.size();
        int left = 0;
        int tempSum = 0;
        int maxlen = 0;
        for(int i=left; i<nums.size(); i++){
            tempSum += nums[i];
            while(tempSum >= newTarget && i>=left){
                if(tempSum == newTarget){
                    maxlen = max(maxlen, i-left+1);
                }
                tempSum -= nums[left];
                left++;
            }
            
        }
        return maxlen == 0 ? -1 : nums.size() - maxlen;
    }
};

复杂度分析

令 n 为数组长度。

  • 时间复杂度:$O(n)$
  • 空间复杂度:$O(1)$

@joeytor
Copy link

joeytor commented Oct 25, 2021

思路

使用滑动窗口的方法, 想要找到最大的窗口, 需要窗口中的和是 t = sum (nums) - target

每次将元素加入窗口, 如果此时的和大于 t, 那么右移窗口的左边界, 直到窗口中的数的和小于等于 t

检查 窗口中的数的和是否等于 t, 如果等于, 那么 跟 min_length 比较并更新 min_length

class Solution:
    def solve(self, nums, target):
        if nums == []:
            return -1 if target != 0 else 0
        
        s,l = 0,0
        t = sum(nums) - target
        min_length = len(nums)+1

        for i, n in enumerate(nums):
            s += n
            while s > t and l <= i:
                s -= nums[l]
                l += 1
            if s == t:
                min_length = min(min_length, len(nums) - (i-l+1))

        return -1 if min_length == len(nums)+1 else min_length

复杂度

时间复杂度: O(n) 一次遍历的时间复杂度

空间复杂度: O(1)

@okbug
Copy link

okbug commented Oct 25, 2021

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int newTarget = 0;
        int sum = 0;
        for(auto e : nums){
            sum += e;
        }
        newTarget = sum - x;
        if(newTarget == 0)return nums.size();
        int left = 0;
        int tempSum = 0;
        int maxlen = 0;
        for(int i = left; i < nums.size(); i++){
            tempSum += nums[i];
            while(tempSum >= newTarget && i >= left){
                if(tempSum == newTarget){
                    maxlen = max(maxlen, i-left+1);
                }
                tempSum -= nums[left];
                left++;
            }
            
        }
        return maxlen == 0 ? -1 : nums.size() - maxlen;
    }
};

@mmboxmm
Copy link

mmboxmm commented Oct 25, 2021

思路

滑动窗口

class Solution:
    def solve(self, nums, target):
        if nums == []:
            return -1 if target != 0 else 0
        
        s,l = 0,0
        t = sum(nums) - target
        min_length = len(nums)+1

        for i, n in enumerate(nums):
            s += n
            while s > t and l <= i:
                s -= nums[l]
                l += 1
            if s == t:
                min_length = min(min_length, len(nums) - (i-l+1))

        return -1 if min_length == len(nums)+1 else min_length

复杂度

  • 时间复杂度: O(n) 一次遍历的时间复杂度
  • 空间复杂度: O(1)

@laofuWF
Copy link

laofuWF commented Oct 26, 2021

# to find min operation: find max sublist length that has sum of total - target
# sliding window: increment right if window sum < total - target, otherwise increment left

# time: O(N)
# space: O(1)
class Solution:
    def solve(self, nums, target):
        total = sum(nums)
        if total < target:
            return -1
        if total == target:
            return len(nums)
        
        left = 0
        curr_sum = 0
        # max valid sublist length that hs sum total - target
        max_length = -1

        for right in range(len(nums)):
            curr_sum += nums[right]
            
            while left < right and curr_sum > total - target:
                curr_sum -= nums[left]
                left += 1
            
            if curr_sum == total - target:
                max_length = max(max_length, right - left + 1)
        
        if max_length == -1:
            return -1
        return len(nums) - max_length

@shawncvv
Copy link

思路

二分法、滑动窗口

代码

Python3

class Solution:
    def solve(self, A, target):
        if not A and not target: return 0
        target = sum(A) - target
        ans = len(A) + 1
        i = t = 0

        for j in range(len(A)):
            t += A[j]
            while i <= j and t > target:
                t -= A[i]
                i += 1
            if t == target: ans = min(ans, len(A) - (j - i + 1))
        return -1 if ans == len(A) + 1 else ans

复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

@yan0327
Copy link

yan0327 commented Oct 26, 2021

LC的1658题
思路:
求两边最小等于求中间最大,先对整个数组求和,减去target。然后开始求滑动窗口的值,

func minOperations(nums []int, x int) int {
    sum := 0
    for i:=0;i<len(nums);i++{
        sum += nums[i]
    }
    if sum == x{
        return len(nums)
    }
    if sum < x{
        return -1
    }
    sum -= x
    l, r := 0,0
    out := 0
    for ;r<len(nums);r++{
        sum -= nums[r]
        for sum < 0&&l <= r{
            sum += nums[l]
            l++
        }
        if sum == 0{
            if r-l+1 > out{
                out = r-l+1
            }
        }
    }
    if out == 0{
        return -1
    }
    return len(nums) - out
}

时间复杂度O(n)
空间复杂度O(1)

@tongxw
Copy link

tongxw commented Oct 26, 2021

思路

其实就是求和 = sum - target,且长度最大的连续子串。

代码

class Solution {
    public int solve(int[] nums, int target) {
        int sum = Arrays.stream(nums).sum();
        if (sum < target) {
            return -1;
        }
        if (sum == target) {
            return nums.length;
        }

        int winSum = 0;
        int maxLen = 0;
        int left = 0;
        for (int right=0; right<nums.length; right++) {
            winSum += nums[right];
            while (winSum >= sum - target && left <= right) {
                if (winSum == sum - target) {
                    maxLen = Math.max(maxLen, right - left + 1);
                }

                winSum -= nums[left];
                left++;
            }
        }

        return maxLen == 0 ? -1 : nums.length - maxLen;
    }
}

TC: O(n)
SC: O(1)

@ai2095
Copy link

ai2095 commented Oct 26, 2021

Number of Operations to Decrement Target to Zero

https://binarysearch.com/problems/Number-of-Operations-to-Decrement-Target-to-Zero

Topics

  • slide window

思路

slide window

代码 Python

class Solution:
    def solve(self, nums, target):
        if sum(nums) < target:
            return -1
        if not nums:
            return -1 if target != 0 else 0
        
        l, r = 0, len(nums) - 1
        result_len = float("inf")
        cur_sum = 0
        while l < len(nums) and r < len(nums):
            cur_sum += nums[r]
            if cur_sum == target:
                result_len = min(result_len, r-l)

            elif cur_sum > target:
                # since this greater is caused by increasing r
                # only shrinking l
                while cur_sum > target:
                    l += 1
                    cur_sum -= nums[l]
                if cur_sum == target:
                    result_len = min(result_len, r-l)
            r += 1 
        return result_len
            

复杂度分析

时间复杂度: O(N)

空间复杂度:O(1)

@Francis-xsc
Copy link

思路

滑动窗口+双指针
最后一个用例超时了,真的不会了

代码

class Solution {
private:
    bool fn(unordered_map<char,int>a,unordered_map<char,int>b){
        for(auto x:b)
        {
            if(a[x.first]<x.second)
                return false;
        }
        return true;
    }
public:
    string minWindow(string s, string t) {
        int windowSize=t.size(),len=s.size();
        if(t.size()>len)
            return "";
        unordered_map<char,int>a,b;
        for(char c:t)
            b[c]++;
        int l=0,r=0,ansL=-1,ansLen=100001;
        while(r<len)
        {
            while(r<len&&!fn(a,b)){
                if(r==len) 
                    break;
                a[s[r]]++;
                r++;
            }
            while(fn(a,b)){
                a[s[l]]--;
                l++;
            }
            if(r-l+1<ansLen){
                ansL=l-1;
                ansLen=r-l+1;
            }
        }
        if (ansL == -1 || ansLen == 100001)
            return "";
        return  s.substr(ansL, ansLen);
    }
};

复杂度分析

  • 时间复杂度:O(N),其中 N 为数组长度。
  • 空间复杂度:O(1)

@nonevsnull
Copy link

思路

  • 拿到题的直觉解法
    • Leetcode 1658
    • 依旧使用双指针,依旧从左到右,依旧缩进
    • 第一眼没看出来是双指针,为什么没看出来?因为,我们要盯着的不是窗口内的元素,而是窗口外的元素和;
    • (递归/backtrack bf 做也可以,但是会TLE)
    • 题目实际上是问你两边的情况,那实际上可以转换为问窗口内?
    • 双指针问题,也有可能是这种,看着窗口外/内的元素的情况;
    • 找窗口内的元素和sum问题 === 全体元素和sum - 窗口外元素和sum,可以切换问题

AC

代码

//双指针非固定滑动窗口
class Solution {
    public int minOperations(int[] nums, int x) {
        long sum = 0, res = Integer.MAX_VALUE;
        for(int i: nums){
            sum += i;
        }   
        if(sum < x) return -1;
        if(sum == x) return nums.length;
        int left = 0, window = 0;
        for(int i = 0;i < nums.length;i++){
            window += nums[i];
            while(window > sum - x){
                window -= nums[left++];
            }
            if(window == sum - x) res = Math.min(res, nums.length - i - 1 + left);
        }
        return (int)res == Integer.MAX_VALUE?-1:(int)res;
        
    }
}

//递归,backtrack
class Solution {
    public int minOperations(int[] nums, int x) {
        Deque<Integer> deq = new LinkedList<>();
        long sum = 0;
        for(int i: nums) {
            deq.addLast(i);
            sum += i;
        }
        if(sum < x) return -1;
        int res = helper(deq, 0, x, nums.length);
        return res == Integer.MAX_VALUE?-1:res;
    }
    
    public int helper(Deque<Integer> deq, int sum, int target, int length){
        if(sum == target) return length - deq.size();
        if(deq.size() == 0) return Integer.MAX_VALUE;
        if(sum > target) return Integer.MAX_VALUE;
        
        // System.out.println(sum);
        int first = deq.pollFirst();
        int l = helper(deq, sum+first, target, length);
        deq.addFirst(first);
        int last = deq.pollLast();
        int r = helper(deq, sum+last, target, length);
        deq.addLast(last);
        
        return l<r?l:r;
    }
}

复杂度

//2pointers
O(N)
O(1)

//backtrack
O(2^N)
O(N)

@kennyxcao
Copy link

Number of Operations to Decrement Target to Zero

Problem Source

Intuition

  • Sliding Window
    1. Find max substring length that with sum == totalSum - target
    2. Subtract ^ from len(nums) => min deletion needed to reach target

Code

class Solution {
  solve(nums, target) {
    if (target === 0) return 0;
    const n = nums.length;
    const totalSum = nums.reduce((acc, num) => acc + num, 0);
    const remain = totalSum - target;
    if (remain < 0) return -1; // impossible to reach target
    if (remain === 0) return n; // need to remove all nums to reach target
    let sum = 0;
    let maxLen = -1;
    let start = 0;
    for (let i = 0; i < n; ++i) {
      sum += nums[i];
      while (sum >= remain) {
        if (sum === remain) {
          maxLen = Math.max(maxLen, i - start + 1);
        }
        sum -= nums[start++];
      }
    }
    return maxLen === -1 ? -1 : n - maxLen;
  }
}

Complexity Analysis

  • Time: O(n)
  • Space: O(1)
  • n = len(nums)

@guangsizhongbin
Copy link

public int solve(int[] nums, int target) {
int sum = Arrays.stream(nums).sum();
if (sum == target) {
return nums.length;
} else if (sum < target) {
return -1;
}

int subSum = sum - target;
// We want to find the longest sub-array whose sum is equal to sumSum
int max = 0;
int l = 0;
int windowSum = 0;
for (int r = 0; r < nums.length; r++) {
    windowSum += nums[r];
    while (windowSum > subSum) {
        windowSum -= nums[l++];
    }
    if (windowSum == subSum) {
        max = Math.max(max, r - l + 1);
    }
}
return max == 0 ? -1 : nums.length - max;

}

@Zippend
Copy link

Zippend commented Oct 26, 2021

思路:
根据题目意思,只能从数组的开始和结尾取出数据,所以最后剩下的元素必然是连续的,因此,我们可以通过求出剩下的最长的子数组,且子数组之和等于sumArray - target,然后用原数组长度减去该最长子数组的长度,即得到了符合target条件的元素数量最少。

代码:

class Solution{

public int minSubArrayLength(int[] nums, int target){

    int n = nums.length;
    int left = 0, right = 0;
    int sum = 0;
    //计算原来数组的和
    for(int i = 0; i < n; i++){
        sum += nums[i];
    }
    int newTarget = sum - target;
    int curSum = 0;
    int maxLength = 0;
    //开始进行滑动窗口,先右边界动,左边界不动
    for(; right < n; right++){
        curSum += nums[right];
        while(curSum >= newTarget && right >= left){
            if(curSum == newTarget){
                maxLength = Math.max(minLength, right - left + 1);
            }
            //开始左窗口收缩
            curSum -= nums[left];
            left++;
        }
    }
    return maxLength == 0 ? -1 : maxLength;
}

}

复杂度分析:

时间复杂度:每个元素在滑动窗口中,进来一次操作,出去一次操作,每个元素最多被操作两次,所以时间复杂度是O(n);
空间复杂度:O(1);

@Auto-SK
Copy link

Auto-SK commented Oct 26, 2021

思路

删除和为 target 的若干数字等价于保留若干和为 sum(A) - target 的数。这样问题就转化为 求连续子数组和为 sum(A) - target 的最长子数组。这种问题可以使用滑动窗口来解决。

代码

class Solution:
    def solve(self, nums, target):
        if not nums and not target:
            return 0
        target = sum(nums) - target
        ans = len(nums) + 1
        i = t = 0
        for j in range(len(nums)):
            t += nums[j]
            while i <= j and t > target:
                t -= nums[i]
                i += 1
            if t == target:
                ans = min(ans, len(nums) - (j - i + 1))
        return -1 if ans == len(nums) + 1 else ans

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

@qixuan-code
Copy link

Number of Operations to Decrement Target to Zero

Ideas

  • the question can be converted: find a substring whose sum equals to sum(nums) - target with max lenghth.

python代码

class Solution:
    def solve(self, nums, target):
        if sum(nums) == target: return len(nums)
        sum_remain = sum(nums)-target
        left, right =0,0
        max_len = 0
        cur_sum = 0
        for right, value in enumerate(nums):
            cur_sum += value
            while cur_sum > sum_remain and left < right:
                cur_sum -= nums[left]
                left += 1
            if cur_sum == sum_remain:
                max_len = max(max_len, right-left + 1)

        return len(nums)-max_len if max_len !=0 else -1

复杂度分析

  • 时间复杂度:O(N)

@Richard-LYF
Copy link

class Solution:
def solve(self, A, target):
if not A and not target: return 0
target = sum(A) - target
ans = len(A) + 1
i = t = 0

    for j in range(len(A)):
        t += A[j]
        while i <= j and t > target:
            t -= A[i]
            i += 1
        if t == target: ans = min(ans, len(A) - (j - i + 1))
    return -1 if ans == len(A) + 1 else ans

@Lydia61
Copy link

Lydia61 commented Oct 26, 2021

Number of Operations to Decrement Target to Zero

思路

  • 删除和为 target 的若干数字等价于保留若干和为 sum(A) - target 的数
  • 求连续子数组和为 sum(A) - target 的最长子数组

代码

class Solution:
    def solve(self, nums, target):
        if not nums and not target:
            return 0
        target = sum(nums) - target
        ans = len(nums) + 1
        i = t = 0
        for j in range(len(nums)):
            t += nums[j]
            while i <= j and t > target:
                t -= nums[i]
                i += 1
            if t == target:
                ans = min(ans, len(nums) - (j - i + 1))
        return -1 if ans == len(nums) + 1 else ans

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

@skinnyh
Copy link

skinnyh commented Oct 26, 2021

Note

  • Think in the other direction, instead of minimizing the length of prefix+suffix, we can maximize the length of a subarray which sum equals to sum(nums) - target. Then this becomes a sliding window problem.
  • The sliding window can be size 0.

Solution

class Solution:
    def solve(self, nums, target):
        # find the longest subarray which sum equals sum(nums) - target
        if not nums and not target:
            return 0
        target = sum(nums) - target
        max_size = float('-inf')
        l = win_sum = 0
        for r in range(len(nums)):
            win_sum += nums[r]
            while l <= r and win_sum > target:
                win_sum -= nums[l]
                l += 1
            if win_sum == target:
                max_size = max(max_size, r - l + 1)
        return len(nums) - max_size if max_size >= 0 else -1

Time complexity: O(N)

Space complexity: O(1)

@comst007
Copy link

Number of Operations to Decrement Target to Zero


思路

滑动窗口

数组各元素的和为tot_sum,该问题转化为求和为tot_sum - target的最长子数组

代码

  • C++
int solve(vector<int>& nums, int target) {
   typedef long long LL;
   LL tot = 0;
   for(auto cur: nums){
       tot += cur;
   } 
   if(tot < target) return -1;
   if(tot == target) return nums.size();

   LL sub_tot = tot - target;
   LL cur_tot = 0;

   int ii, jj;
   int n = nums.size();
   int ans = 0;

   
   for(jj = 0, ii = 0; ii < n; ++ ii){
       cur_tot += nums[ii];
       while(jj < ii && cur_tot > sub_tot){
           cur_tot -= nums[jj];
           ++ jj;
       }
       if(cur_tot == sub_tot){
           ans = max(ans, ii - jj + 1);
       }
      

   }
   if(ans == 0) return -1;
   return n - ans;
}

复杂度分析

n为nums长度。

  • 时间复杂度 O(n)。
  • 空间复杂度 O(1)。

@xinhaoyi
Copy link

【Day 47】Number of Operations to Decrement Target to Zero

Number of Operations to Decrement Target to Zero | binarysearch

Task

You are given a list of positive integers nums and an integer target. Consider an operation where we remove a number v from either the front or the back of nums and decrement target by v.

Return the minimum number of operations required to decrement target to zero. If it's not possible, return -1.

Constraints

  • n ≤ 100,000 where n is the length of nums

Example 1

Input

nums = [3, 1, 1, 2, 5, 1, 1]
target = 7

Output

3

Explanation

We can remove 1, 1 and 5 from the back to decrement target to zero.

思路一

因为只允许我动头尾的元素,所以剩下的元素是一个连续子列,其和为:total - target

我们用一个滑动窗口去找到一个最长的连续子列,使得他们的和恰好是 total - target,即可

代码

class Solution {
    public int solve(int[] nums, int target) {
        int numsSum = 0;
        //get the total of the nums
        for(int num : nums){
            numsSum += num;
        }
        //get the target of the subString 
        int subStringTarget = numsSum - target;
        if(subStringTarget == 0){
            //it means all the element should be removed from the array
            return nums.length;
        }

        if(subStringTarget < 0){
            //it means the whole array can't meet the requirement
            return -1;
        }

        //using sliding window
        //The total of subString
        int subStringSum = 0;
        int maxLengthOfSubString = 0;
        //close right and open right
        for(int left = -1, right = 0; right < nums.length ; right ++){
            //once the window is generated check the total of the window
            subStringSum += nums[right];
            //if left == right, the window is empty
            while(left < right && subStringSum >= subStringTarget){
                //move left point to narrow the window
                if(subStringSum == subStringTarget){
                    //get the maxLength
                    maxLengthOfSubString = Math.max(maxLengthOfSubString, right - left);
                }
                left ++;
                subStringSum -= nums[left];
            }
        }

        return maxLengthOfSubString == 0 ? -1 : nums.length - maxLengthOfSubString;

    }
}

复杂度分析

时间复杂度: O(n)

空间复杂度:O(1)

@mokrs
Copy link

mokrs commented Oct 26, 2021

int minOperations(vector<int>& nums, int x) {
    int sum = 0;	
    for (int i = 0; i < nums.size(); ++i){
        sum += nums[i];
    }

    if (sum < x){
        return -1;
    }
    int left = 0, right = 0;
    int sum2 = 0, res = INT_MAX;
    while (right < nums.size()) {
        sum2 += nums[right++];

        while (sum2 > sum - x && left <= right) {
            sum2 -= nums[left++];
        }
        if (sum2 == sum - x) {
            res = (res > nums.size() - right + left - 1) ? nums.size() - right + left : res;

        }
    }

    return res == INT_MAX ? -1 : res;
}

@jaysonss
Copy link

思路

问题可以转化成求一个连续的最大子数组,它的和等于sum(nums)-target,既然是求连续子数组,那自然就可以想到使用滑动窗口来解

代码

class Solution {
    public int solve(int[] nums, int target) {
        if(target == 0)return 0;
        if(nums.length==0)return  -1;
        
        int sum = 0;
        for(int num : nums){
            sum+=num;
        }

        int anchor = sum - target;
        if(anchor<0)return -1;

        int l = 0,r = 0,total =0,ans = Integer.MAX_VALUE;
        while(r<nums.length){
            total += nums[r];
            while(total>anchor && l<=r){
                total-=nums[l];
                l++;
            }
            if(total == anchor){
                ans = Math.min(ans,nums.length - r + l - 1);
            }
            r++;
        }
        return ans == Integer.MAX_VALUE ? -1 : ans;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

@leolisgit
Copy link

思路

逆向思维。题目求从头尾删掉最少的元素使得他们的和为target。等价于,求一个最长连续子数组,使得和为 sum - target。
窗口收缩条件是,当前窗口的值 > sum - target。

代码

class Solution {
    public int solve(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return target == 0 ? 0 : -1;
        }

        int sum = 0;
        for (int n : nums) {
            sum += n;
        }

        if (sum == target) return nums.length;

        int newTarget = sum - target;

        int start = 0;
        int end = 0;
        sum = 0;
        int len = -1;
        while (end < nums.length) {
            sum += nums[end];
            end++;
            while (start < end && sum > newTarget) {
                sum -= nums[start];
                start++;
            }
            if (sum == newTarget) {
                len = Math.max(len, end - start);
            }
        }
        return len > 0 ? nums.length - len : len;
    }
}

复杂度

时间:O(n)
空间:O(1)

@famine330
Copy link

class Solution:
    def solve(self, nums, target):
        if not nums and not target:
            return 0
        target = sum(nums) - target
        ans = len(nums) + 1
        l = 0
        total = 0
        for r in range(len(nums)):
            total += nums[r]
            while l <= r and total > target:
                total -= nums[l]
                l += 1
            if total == target:
                ans = min(ans, len(nums) - (r - l + 1))
        return -1 if ans == len(nums) + 1 else ans

@JianXinyu
Copy link

https://binarysearch.com/problems/Number-of-Operations-to-Decrement-Target-to-Zero
题目说得不清楚,应该还有以下两个条件:

  • $sum(nums) &lt;= 2^{31}-1$
  • 是恰好等于0,负数也不行

思路

滑动窗口
由于是从两边减,中间保证连续,不妨把中间的和设为target,也就是target = sum-target。
这样就可以从头遍历数组,累加得到ts

  • 如果ts小于target,就继续累加
  • 如果ts大于target,就从左端开始缩小
  • 如果ts等于target,就记录其长度

Code

int solve(vector<int>& nums, int target) {
    const int n = nums.size();
    if(target == 0)
        return 0;
    if(n == 0 || (n == 1 && nums[0] < target))
        return -1;

    int sum = std::accumulate(nums.begin(), nums.end(), 0);
    if(sum < target)
        return -1;

    target = sum - target;
    int ans = n+1, ts = 0, j = 0;
    
    for(int i = 0; i < n; ++i){
        ts += nums[i];
        while(i >= j && ts > target){
            ts -= nums[j++];
        }
        if(ts == target)
            ans = min(ans, n-(i-j+1));
    }
    return ans == n+1 ? -1 : ans;
}

T: average: O(n) worst: O(n^2) 最坏的情况是nums右端是特别大的数,比如$nums=[1,1,1,1,100], target = 100$
S: O(1)

@chakochako
Copy link

class Solution:
    def solve(self, nums, target):
        if target == 0:
            return 0
        psum = sum(nums)
        if psum < target:
            return -1
        ans = len(nums) + 1
        ssum = 0
        suffixcnt = 0
        for i in range(len(nums) - 1, -1, -1):
            psum -= nums[i]
            while psum + ssum < target:
                ssum += nums[-1 - suffixcnt]
                suffixcnt += 1
            if psum + ssum == target:
                ans = min(ans, i + suffixcnt)
        if ans > len(nums):
            ans = -1
        return ans

@ymkymk
Copy link

ymkymk commented Oct 26, 2021

思路

打卡(参考官网)

代码

``


class Solution {
    public int solve(int[] nums, int target) {
        int n = nums.length;
        if (n == 0) {
            if (target == 0)
                return 0;
            else
                return -1;
        }
        if (target == 0)
            return 0;
        int sum = 0;
        for (int num : nums) sum += num;
        if (sum == target)
            return n;
        target = sum - target;
        HashMap<Integer, Integer> map = new HashMap<>();
        int t = 0;
        int ans = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) {
            t += nums[i];
            if (t == target)
                ans = Math.min(n - 1 - i, ans);
            if (map.containsKey(t - target))
                ans = Math.min(ans, n - (i - map.get(t - target)));
            map.put(t, i);
        }
        return ans == Integer.MAX_VALUE ? -1 : ans;
    }
}

复杂度分析

时间复杂度:O(n)

空间复杂度:O(1)

@Venchyluo
Copy link

刚开始理解错题意了,前后其实可以一起取,但是要保证前连续 && 后连续。
可以想成求数组中-中间连续的最长一段加起来总和为sums-target,这样就可以用sliding window 扫一遍,如果temp_sums > sums- target 就删掉前面的数字再往后加,中间保留一个最长中间联系/最短前后个数总和就可以了。

class Solution:
    def solve(self, nums, target):
        if target == 0: return 0
        if sum(nums) < target: return -1
        part = sum(nums) - target
        l,r,temp = 0, 0, 0
        res = float('inf')
        for r in range(len(nums)):
            temp += nums[r]
            while temp > part:
                temp -= nums[l]
                l += 1
            if temp == part:
                res = min(res,(len(nums)-(r-l+1)))
        
        return res if res != float('inf') else -1
          
    

Time complexity: O(N)
Space complexity: O(1)

@yibenxiao
Copy link

【Day 47】Number of Operations to Decrement Target to Zero

思路

官方题解

代码

class Solution:
    def solve(self, A, target):
        if not A and not target: return 0
        target = sum(A) - target
        ans = len(A) + 1
        i = t = 0

        for j in range(len(A)):
            t += A[j]
            while i <= j and t > target:
                t -= A[i]
                i += 1
            if t == target: ans = min(ans, len(A) - (j - i + 1))
        return -1 if ans == len(A) + 1 else ans

复杂度

时间复杂度:O(N)

空间复杂度:O(1)

@BreezePython
Copy link

思路

双指针模拟滑窗

代码

class Solution:
    def solve(self, nums, target):
        if not nums and not target:
            return 0
        target = sum(nums) - target
        ans = len(nums) + 1
        l = 0
        total = 0
        for r in range(len(nums)):
            total += nums[r]
            while l <= r and total > target:
                total -= nums[l]
                l += 1
            if total == target:
                ans = min(ans, len(nums) - (r - l + 1))
        return -1 if ans == len(nums) + 1 else ans

复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

@falsity
Copy link

falsity commented Oct 26, 2021

思路

题目可以转化为寻找最长的连续的数组,满足 nums所有元素的和sumAll - target

最后的结果就是数组的长度n - 满足条件最长的连续数组长度max

import java.util.*;

class Solution {
    public int solve(int[] nums, int target) {
        if(target == 0){
            return 0;
        }
        int n = nums.length;
        int max = Integer.MIN_VALUE;
        int sumAll = 0;
        for(int num : nums){
            sumAll += num;
        }
        int target2 = sumAll - target;

        int j = 0, count = 0, sum = 0;
        for (int i = 0; i < n; i++) {
            sum += nums[i];
            count++;
            while (sum > target2 && j < n) {
                sum -= nums[j++];
                count--;
            }
            if (sum == target2) {
                max = Math.max(max, count);
            }
        }      
        return max >= 0 ? n - max : -1;
    }
}

@Yufanzh
Copy link

Yufanzh commented Oct 26, 2021

Intuition

Changing the way of thinking as "finding the longest subarray whose sum == sum(nums) - target" can convert this problem to a sliding window problem.
But when writing the code, considering all the possible boundary conditions.

Algorithm in python3

class Solution:
    def solve(self, nums, target):
        # treat it as find the max length of subarray where the sum of them is = sum - target
        if nums == None or len(nums) == 0:
            if target == 0:
                return 0
            else:
                return -1
        sum_array = sum(nums)
        residual = sum_array - target
        if sum_array < target:
            return -1
        if sum_array == target:
            return len(nums)

        left = 0
        right = 0
        ans = 0
        win_sum = 0
        ans = -1
        while right < len(nums):
            win_sum += nums[right]
            right += 1
            while win_sum > residual and left < right:
                win_sum -= nums[left]
                left += 1
            if win_sum == residual:
                ans = max(ans, right - left)
        
        if ans > 0:
            return len(nums) - ans
        else:
            return ans

Complexity Analysis:

  • Time complexity: O(n)
  • Space complexity: O(1)

@xj-yan
Copy link

xj-yan commented Oct 26, 2021

class Solution {
    public int solve(int[] nums, int target) {
        if (target == 0) return 0;
        int sum = 0;
        for (int n : nums) sum += n;

        if (sum == target) return nums.length;
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, -1);

        int prefixSum = 0, targetSum = sum - target, maxLen = -1;
        for (int i = 0; i < nums.length; i++){
            prefixSum += nums[i];
            if (map.containsKey(prefixSum - targetSum)){
                maxLen = Math.max(maxLen, i - map.get(prefixSum - targetSum));
            }
            if (!map.containsKey(prefixSum)) map.put(prefixSum, i);
        }

        return maxLen == -1 ? -1 : nums.length - maxLen;
    }
}

Time Complexity: O(n), Space Complexity: O(n)

@ZETAVI
Copy link

ZETAVI commented Oct 26, 2021

思路

其实就是求和 = sum - target,且长度最大的连续子串。

代码

class Solution {
    public int solve(int[] nums, int target) {
        int sum = Arrays.stream(nums).sum();
        if (sum < target) {
            return -1;
        }
        if (sum == target) {
            return nums.length;
        }

        int winSum = 0;
        int maxLen = 0;
        int left = 0;
        for (int right=0; right<nums.length; right++) {
            winSum += nums[right];
            while (winSum >= sum - target && left <= right) {
                if (winSum == sum - target) {
                    maxLen = Math.max(maxLen, right - left + 1);
                }

                winSum -= nums[left];
                left++;
            }
        }

        return maxLen == 0 ? -1 : nums.length - maxLen;
    }
}

复杂度分析

TC: O(n)
SC: O(1)

@ozhfo
Copy link

ozhfo commented Oct 26, 2021

public int solve(int[] nums, int target) {
        if (target == 0) return 0;
        if (nums.length == 0) return -1;
        int arrSum = 0;
        for (int num : nums) {
            arrSum += num;
        }
        // 目标数组的和
        int subSumTarget = arrSum - target;
        if (subSumTarget < 0) return -1;
        int l = 0, r = 0, subSum = 0, opTimes = Integer.MAX_VALUE;
        while (r < nums.length) {
            subSum += nums[r];
            while (subSum > subSumTarget && l <= r) {
                // 如果超过了 扔掉左边
                subSum -= nums[l];
                l++;
            }
            if (subSum == subSumTarget) {
                opTimes = Math.min(opTimes, nums.length - r + l - 1);
            }
            r++;
        }
        return opTimes == Integer.MAX_VALUE ? -1 : opTimes;
    }

@joriscai
Copy link

思路

  • 滑动窗口
  • 这题要清楚题意。根据题意,
    • 只能从前、后删除元素
    • 删除元素总和为target
    • 因此中间部分是连续的,这部分的总和为sum - target
    • 找连续的子串,可以使用滑动窗口来解决

代码

javascript

class Solution {
  solve(nums, target) {
    if (target === 0) return 0
    // 根据题意是要删除的元素和等于target
    // 同时只能从前或者从后面删除元素
    // 则中间部分是连续的,即sum - target的部分是连续的
    // 这个连续的部分可以使用滑动窗口
    const sum = nums.reduce((prev, cur) => prev + cur, 0)
    const remain = sum - target

    const len = nums.length
    // 当剩余的数为0时,说明整个数组都要删除才能符合
    if (remain === 0) return len
    // 当剩余的数小于0,说明整个数组都要删除都不能符合
    if (remain < 0) return  -1

    let left = 0
    let right = 0
    let minLen = Infinity
    let count = 0
    while (right < len) {
      count += nums[right]
      while (count > remain) {
        count -= nums[left]
        left++;
      }

      if (count === remain) {
        minLen = Math.min(len - (right - left + 1), minLen)
      }

      right++
    }

    return minLen === Infinity ? -1 : minLen
  }
}

复杂度分析

  • 时间复杂度:O(n),在滑动窗口时,最坏情况是快慢指针都要走一遍s,故为2n,即O(n)。
  • 空间复杂度:O(1),只需要常数空间

@L-SUI
Copy link

L-SUI commented Oct 27, 2021

/**
 * @param {number[]} nums
 * @param {number} x
 * @return {number}
 */
var minOperations = function(nums, x) {
    const len = nums.length
    const total = nums.reduce((prev,cur) => prev+cur,0)
    if(total<x) return -1 //边界,如果总和都不达 x, 那就直接跑路吧
    let ret = Infinity //最少的操作数
    let sum = 0
    let l =r =0
    while(r<len){
        sum+=nums[r]
        while(total-sum<x){
            // 外面的值已经小于 x 了,所以需要收缩窗口
            sum-=nums[l]
            l++
        }
        if(total-sum === x){
            // 符合要求
            ret= Math.min(ret,len-(r-l+1))
        }
        r++
    }
    return ret=== Infinity?-1:ret
};

@q815101630
Copy link

补作业

找到一个最大的滑动窗口

class Solution:
    def solve(self, nums, target):
        # sum(deleted nums) == 7
        # sum(nums) -7  = sum(left nums)
        if target == 0:
            return 0
        
        left = 0
        newTarget = sum(nums)-target
        curSum = 0
        ans = -1
        for right in range(len(nums)):
            curSum+= nums[right]
            if curSum == newTarget:
                curLen = right-left+1
                ans = max(ans, curLen)
            elif curSum > newTarget:
                while left <= right and curSum > newTarget:
                    curSum -= nums[left]
                    left+=1
                if curSum == newTarget:
                    ans = max(ans, right-left+1)
        if ans == -1:
            return ans

        return len(nums)-ans 

Time: O(n)
Space: O(1)

@asaoba
Copy link

asaoba commented Oct 27, 2021

思路

  • 滑动窗口
  • 问题转换:把题目要求转换为求和等于"数组值总和-target"的最长连续子数组
  • 代码实现思路
  • 滑动条件:此时子数组的总和≠数组总和-target
    小于——右端滑动
    大于——左端滑动
    等于——判断子数组长度是否为当前最大

代码

import java.util.*;
class Solution {
    public int solve(int[] nums, int target) {
        if(target==0)
            return 0;
        if(nums.length==0)
            return -1; 
        int sum=0;
        for(int i=0;i<nums.length;i++)
            sum+=nums[i];
        
        int newT=sum-target;
        if(newT<0)
            return -1;
        
        int l=0,r=0;
        int len=Integer.MIN_VALUE;
        int tmpSum=0;
        while(r<nums.length){
            tmpSum+=nums[r];
            while(tmpSum>newT&&l<=r){
                tmpSum-=nums[l++];
            }
            if(tmpSum==newT){
                len=Math.max(len,r-l+1);
            }
            r++;
        }
        return len<0?-1:nums.length-len;      
    }
}

复杂度

  • 时间复杂度O(n)
  • 空间复杂度O(1)

@sumukeio
Copy link

int minOperations(vector& nums, int x) {
int sum = 0;
for (int i = 0; i < nums.size(); ++i){
sum += nums[i];
}

if (sum < x){
    return -1;
}
int left = 0, right = 0;
int sum2 = 0, res = INT_MAX;
while (right < nums.size()) {
    sum2 += nums[right++];

    while (sum2 > sum - x && left <= right) {
        sum2 -= nums[left++];
    }
    if (sum2 == sum - x) {
        res = (res > nums.size() - right + left - 1) ? nums.size() - right + left : res;

    }
}

return res == INT_MAX ? -1 : res;

}

@Bingbinxu
Copy link

方法
利用滑动窗口,计算newT=sums(nums)-target的最长字串,往右滑动判定条件>newT,往左移动判定条件也是<newT
代码

实现语言: C++
int solve(vector<int>& nums, int target) {
    int N = nums.size();
    int newT = accumulate(nums.begin(), nums.end(), 0) - target;
    if(newT == 0)
    {
        return N;
    }
    int sum = 0;
    int maxlen = 0;
    int left = 0;
    for(int i = 0;i < N;i++)
    {
        sum += nums[i];
        while(sum >= newT && i >= left)
        {
            if(sum == newT)
            {
                maxlen = max(maxlen, i - left +1);
            }
            sum -= nums[left];
            left++;
        }
    }
    return maxlen ==0 ? -1 : N - maxlen; 
}

复杂度分析
时间复杂度: O(N),N为S串长度
空间复杂度: O(1)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests