给你一个整数数组 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_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= \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;
}
};