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

题目描述

给一个整数数组nums和整数x
需要从数组的左边或者右边删除元素,然后用x减去删除的元素
问如果x刚好成删到0,怎么删最短?

f1-反向思考+双指针

基本分析

  1. 反向思考?找一个最长的子数组满足和= sum(nums) - x
  2. 为啥可以双指针?(1)元素都是整数,序列和是单调的;(2)元素连续

代码

def minOperations(self, nums: List[int], x: int) -> int:
n = len(nums)
l = 0
target = sum(nums) - x
if target < 0:
return -1
s = 0
ans = -1
for r, x in enumerate(nums):
s += x
while s > target:
s -= nums[l]
l += 1
if s == target:
ans = max(ans, r - l + 1)
if ans < 0:
return -1
else:
return n - ans

总结

  1. 反向思考
f2-直接计算+双指针

基本分析

  1. 怎么直接计算?(1)先找到后缀中满足和<=x的最长后缀的索引;(2)枚举前缀l,while中一直往后挪右指针,找到和不大于x的索引,while出来后如果=,更新答案。

代码

class Solution:
def minOperations(self, nums: List[int], x: int) -> int:
s, n = 0, len(nums)
# 找到最远的满足后缀和<=x的索引
r = n
while r > 0 and s + nums[r - 1] <= x:
r -= 1
s += nums[r]
# 出来的s不一定就满足>=的要求
if r == 0 and s < x:
return -1
# 出来的值可能会等,可能会>
if s == x:
ans = n - r
else:
ans = inf
for l in range(n):
s += nums[l]
while r < n and s > x:
s -= nums[r]
r += 1
# 出来的s不一定就<=x
if s > x:
break
if s == x:
ans = min(ans, l + 1 + n - r)
if ans == inf:
return -1
else:
return ans

总结

  1. 在找后缀的时候,r是最远的满足s<=x的的位置
  2. 为啥出来的r也可能不满足要求?r已经计算到了0,s就是整个元素的和,如果<x, 表示不能删
  3. 给ans赋初值的时候有啥细节?如果s本身就是一个答案,需要考虑进来,就是n-r。如果不是,因为要求最小值,初值给inf
  4. 计算结果的思路?枚举左端点,委会两边的和s,这个时候s可能会< = 或者 > x (1)小于时候,继续枚举;(2)=更新答案;(3)> 时候,右指针需要往右(但不能越界),更新s;出来的s可能是<=x的情况,如果是=继续更新答案
posted @   zhangk1988  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示