AlgoMooc
你已开通华为OD训练营权益,还差最后一步——完成入营激活(兑换课程 + 加飞书 + 登记服务群),即可解锁全部课程与专属服务。去激活 →
← OD 20 天课程

华为 OD 训练营 · 题解精讲

LC1658. 将x减到0的最小操作数

LC1658. 将x减到0的最小操作数

题目描述

给你一个整数数组 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 <= 10^(5) 1 <= nums[i] <= 10^(4) 1 <= x <= 10^(9)

题目解析

解题思路

本题要求从数组两端移除元素,使移除元素之和等于 x,且操作次数最少。等价于在数组中寻找一个最长的连续子数组,其和为 sum(nums) - x,因为剩余部分就是需要移除的元素。这样,最小操作数 = 数组长度 - 最长子数组长度。

采用不定长滑动窗口(双指针)实现:维护窗口内元素和 windows_sum,当和大于目标值时收缩左边界,当和等于目标值时更新最大窗口长度。

关键步骤

1. 计算 target_sum = sum(nums) - x。若 target_sum == 0,直接返回 len(nums)(全部移除)。 2. 初始化左指针 left = 0,窗口和 windows_sum = 0,最大窗口长度 windows_len_max = 0。 3. 右指针 right 遍历数组:

  • A1:将 nums[right] 加入窗口和。
  • A2:当窗口和大于目标值时,不断右移左指针并减去对应元素。
  • A3:若窗口和等于目标值,更新最大窗口长度。

4. 遍历结束后,若最大窗口长度为 0,返回 -1;否则返回 len(nums) - windows_len_max

示意图(以示例1 nums=[1,1,4,2,3], x=5 为例,target_sum=6):


初始:窗口 [1,1,4] 和=6 → 长度3
最终:窗口 [1,1,4] 长度3 → 操作数=5-3=2

复杂度分析

  • 时间复杂度:O(n),每个元素最多被左右指针各访问一次。
  • 空间复杂度:O(1),仅使用常数个变量。

参考代码

# 题目:LC1658. 将x减到0的最小操作数
# 难度:中等
# 作者:许老师-闭着眼睛学数理化
# 算法:不定滑窗
# 代码看不懂的地方,请直接在群上提问


# 本质上是求【和为target_sum = sum(nums) - x的滑动窗口的最大长度】
# 用变量 windows_sum 表示滑窗中所有元素的和即可

class Solution:
    def minOperations(self, nums: List[int], x: int) -> int:
        target_sum = sum(nums)-x
        if target_sum == 0:
            return len(nums)

        windows_sum = 0
        windows_len_max = 0
        left = 0

        for right, num in enumerate(nums):
            # A1
            windows_sum += num
            # A2
            while(left <= right and windows_sum > target_sum):
                windows_sum -= nums[left]
                left += 1
            # A3
            if windows_sum == target_sum:
                windows_len_max = max(right-left+1, windows_len_max)
        return -1 if windows_len_max == 0 else len(nums)-windows_len_max