题目地址
https://binarysearch.com/problems/Number-of-Operations-to-Decrement-Target-to-Zero
题目描述
思路
题目要求去除数组nums的左右两端元素,并且去除的元素和为target,也就是留下中间的子数组,其和为sum(nums) - target;
题目还要求去除的元素个数越小越好,也就是留下的中间子数组的长度越大越好;
那么问题就转化为了找数组中间和为sum(nums) - target的最长子数组,令该和为我们的新目标new_target,步骤如下:
- 求出新目标new_target = sum(nums) - target,如果new_target == 0,也就是需要找到和为0的子数组,那就是把所有元素都去除了,返回数组长度n
- 接下来就是通过滑动窗口找子数组了,令左右指针指向滑动窗口的左右边界,从索引0开始滑窗
- right指针正常遍历数组,当滑动窗口内的和tmp_sum大于等于new_target的时候,开始缩紧左边界
- 如果tmp_sum正好与new_target相等,找到第一个符合要求的子数组,更新子数组最大长度max_len
- 左指针left右移,tmp_sum也相应的减小,当tmp_sum比new_target小或者left > right时循环结束,right继续遍历
- 最后返回去除的元素个数 n - max_len,如果max_len为0,说明没有找到符合要求的子数组,返回 - 1
代码(Python)
class Solution:
def solve(self, nums, target):
new_target = sum(nums) - target
if new_target == 0:
return len(nums)
tmp_sum = 0
max_len = 0
left = 0
for right, num in enumerate(nums):
tmp_sum += num
while tmp_sum >= new_target and left <= right:
if tmp_sum == new_target:
max_len = max(max_len, right - left + 1)
tmp_sum -= nums[left]
left += 1
return len(nums) - max_len if max_len else -1
代码(Java)
import java.util.*;
class Solution {
public int solve(int[] nums, int target) {
int n = nums.length;
int newTarget = Arrays.stream(nums).sum() - target;
if(newTarget == 0) return n;
int left = 0, tmpSum = 0, maxLen = 0;
for(int right = 0; right < n; right++){
tmpSum += nums[right];
while(tmpSum >= newTarget && left <= right){
if(tmpSum == newTarget){
maxLen = Math.max(maxLen, right - left + 1);
}
tmpSum -= nums[left];
left++;
}
}
return maxLen == 0 ? -1 : n - maxLen;
}
}
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)