616 字
3 分钟
1658. 将 x 减到 0 的最小操作数
1658. 将 x 减到 0 的最小操作数
题目描述
给你一个整数数组 nums 和一个整数 x。每一次操作时,你应当移除数组 nums 最左边或最右边的元素,然后从 x 中减去该元素的值。
如果可以将 x 恰好减到 0,返回最小操作数;否则,返回 -1。
核心思想
正难则反 + 不定长滑动窗口。
从两端移除元素使和为 x,等价于在数组中间找一个最长子数组,其和为 total - x。
设 target = total - x:
- 若
target < 0:无解,返回-1 - 若
target == 0:需移除全部元素,返回n - 否则:用滑动窗口找和为
target的最长子数组,答案 =n - 最长子数组长度
算法步骤
- 计算
total = sum(nums),target = total - x - 特判
target < 0返回-1,target == 0返回n - 初始化
left = 0,window = 0,ans = -1 - 遍历
right从0到n-1:window += nums[right]- 当
window > target时:window -= nums[left],left += 1 - 若
window == target:ans = max(ans, right - left + 1)
- 若
ans == -1返回-1,否则返回n - ans
逐步举例
以 nums = [1, 1, 4, 2, 3], x = 5 为例:
total = 11, target = 11 - 5 = 6
| right | nums[right] | window | >6? | 收缩 | left | window==6? | ans |
|---|---|---|---|---|---|---|---|
| 0 | 1 | 1 | 否 | — | 0 | 否 | -1 |
| 1 | 1 | 2 | 否 | — | 0 | 否 | -1 |
| 2 | 4 | 6 | 否 | — | 0 | 是 | 3 |
| 3 | 2 | 8 | 是 | l=1, window=7; l=2, window=6 | 2 | 是 | 3 |
| 4 | 3 | 9 | 是 | l=3, window=5 | 3 | 否 | 3 |
最终 ans = 3(子数组 [1,1,4]),返回 5 - 3 = 2。
验证:移除两端 [2, 3],和 = 5 ✓,操作数 = 2。
复杂度分析
- 时间复杂度:
O(n)。每个元素最多进出窗口各一次。 - 空间复杂度:
O(1)。
参考
代码实现
from typing import List
class Solution: def minOperations(self, nums: List[int], x: int) -> int: total = sum(nums) target = total - x if target < 0: return -1 if target == 0: return len(nums)
n = len(nums) ans = -1 left = window = 0 for right in range(n): window += nums[right] while window > target: window -= nums[left] left += 1 if window == target: ans = max(ans, right - left + 1) return -1 if ans == -1 else n - ansimport sysimport unittestfrom pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from solution import Solution
class TestMinOperations(unittest.TestCase): def test_example1(self): nums = [1, 1, 4, 2, 3] x = 5 self.assertEqual(Solution().minOperations(nums, x), 2)
def test_example2(self): nums = [5, 6, 7, 8, 9] x = 4 self.assertEqual(Solution().minOperations(nums, x), -1)
def test_example3(self): nums = [3, 2, 20, 1, 1, 3] x = 10 self.assertEqual(Solution().minOperations(nums, x), 5)
def test_remove_all(self): nums = [1, 2, 3] x = 6 self.assertEqual(Solution().minOperations(nums, x), 3)
def test_remove_first(self): nums = [5, 2, 3, 1, 1] x = 5 self.assertEqual(Solution().minOperations(nums, x), 1)
def test_single_element(self): nums = [1] x = 1 self.assertEqual(Solution().minOperations(nums, x), 1)
def test_single_element_impossible(self): nums = [1] x = 2 self.assertEqual(Solution().minOperations(nums, x), -1)
if __name__ == "__main__": unittest.main() 1658. 将 x 减到 0 的最小操作数
https://h1s97x.github.io/posts/coding/coding-1658-min-operations/