文章目录
- 题目描述
 - 题目难度——中等
 - 方法一:反向思考,双指针求最长子数组
 - 代码/Python
 - 代码/C++
 
- 方法二:滑动窗口
 - 代码
 
- 总结
 
- 我把这篇也归到面试题那一栏,因为觉得这题的思路和思考方式还挺好的,或许能用到其他题上
 
题目描述
给你一个整数数组 nums 和一个整数 x 。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。请注意,需要 修改 数组以供接下来的操作使用。
如果可以将 x 恰好 减到 0 ,返回 最小操作数 ;否则,返回 -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为0,求这个删除操作的最小次数。换一个说法,不就是求最少的首部和尾部的元素之和为x的元素个数吗,所以我们可以先对数组求和,记为total,再进一步,题目就变成求和为total - x的最长子数组,于是就可以用双指针来做。
   这里虽然想到了这个办法,但是因为双指针的经验不多,所以借鉴了一下讨论区里一个大佬的代码思路,大佬的题解传送门。
代码/Python
class Solution:
    def minOperations(self, nums: List[int], x: int) -> int:
        n = len(nums)
        total = sum(nums)	# 实测这里将sum函数换成for循环手动求和的话,结果会快很多
        target = total - x
        if target < 0:
            return -1
        res = -1
        p1 = total = 0
        for p2 in range(n):
            total += nums[p2]
            while total > target:
                total -= nums[p1]
                p1 += 1
            
            if total == target:
                res = max(res, p2 - p1 + 1)
        return -1 if res < 0 else n - res
 

代码/C++
class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int n = nums.size(), target, p1, p2, res, total;
        p1 = total = 0, res = -1;
        while(p1 < n){
            total += nums[p1++];
        }
        target = total - x;
        if(target < 0){
            return -1;
        }
        total = p1 = 0;
        for(p2 = 0; p2 < n; p2++){
            total += nums[p2];
            while(total > target){
                total -= nums[p1++];
            }
            if(total == target){
                res = max(res, p2 - p1 + 1);
            }
        }
        return res < 0 ? -1 : n - res;
    }
};
 

方法二:滑动窗口
其实滑动窗口的思路跟上面那个差不多,只不过滑动窗口是正向思路,顺着题目的意思。具体的,同样先求和total,如果total < x,即整体都不够x,肯定无法满足要求。这里直接引用官方的滑动窗口题解,官方链接
代码
class Solution:
    def minOperations(self, nums: List[int], x: int) -> int:
        n = len(nums)
        total = 0
        for num in nums:
        	total += num
        if total < x:
            return -1
        
        right = 0
        lsum, rsum = 0, total
        res = n + 1
        for left in range(-1, n - 1):
            if left != -1:
                lsum += nums[left]
            while right < n and lsum + rsum > x:
                rsum -= nums[right]
                right += 1
            
            if lsum + rsum == x:
                res = min(res, left + 1 + n - right)
        
        return res if res <= n else -1
 
总结
两种方法一个正向,一个反向,个人觉得反向的思路要更好一点,更容易理解一些,都需要遍历一遍,所以时间是O(N),都只用到了常量变量,所以空间是O(1)。



















