当前位置: 首页 > news >正文

Kimi LeetCode 3410. 删除所有值为某个元素后的最大子数组和 Python3实现

以下是 LeetCode 3410. 删除所有值为某个元素后的最大子数组和 的 Python3 实现。

题目理解

给定整数数组 `nums`,可以至多一次选择某个值 `X`,删除数组中所有值为 `X` 的元素(删除后数组必须非空),求能得到数组的最大子数组和。

- 示例1:`nums = [-3,2,-2,-1,3,-2,3]`,删除所有 `-2` 后得到 `[-3,2,-1,3,3]`,最大子数组和为 `2+(-1)+3+3 = 7`。
- 示例2:`nums = [1,2,3,4]`,不删除任何元素,最大子数组和为 `10`。

解题思路

这道题的核心是线段树维护最大子段和 :

1. 不删除时:就是经典的「最大子数组和」(LeetCode 53),可用动态规划或线段树解决。
2. 删除某个值 X 时:等价于将数组中所有值为 `X` 的位置设为 `0`,然后求最大子数组和。
3. 枚举所有可能的 X:用哈希表按值分组记录下标,对每个不同的值,将其所有出现位置在线段树中更新为 `0`,查询全局最大子段和,然后恢复。

线段树每个节点需要维护 4 个信息:
- `sm`:区间总和
- `lv`:从区间左边界开始的最大子段和
- `rv`:以区间右边界结束的最大子段和
- `ans`:区间内的最大子段和

合并两个区间时,最大子段和有三种来源:完全在左区间、完全在右区间、横跨两个区间。

注意:Python 中这道题卡常,需要手写 `max` 函数(用 `lambda` 或普通函数),否则用内置 `max` 会超时 。

Python3 代码

```python
class Node:
def __init__(self, sm, lv, rv, ans):
self.sm = sm # 区间和
self.lv = lv # 从左边界开始的最大子段和
self.rv = rv # 以右边界结束的最大子段和
self.ans = ans # 区间内的最大子段和

class Solution:
def maxSubarraySum(self, nums):
n = len(nums)

# 特殊情况:全是负数时,子段必须非空,只能选最大的负数
mx = -10**9
for x in nums:
mx = mx if mx > x else x
if mx <= 0:
return mx

# 手动比大小,效率更高,不这么写 Python 会超时
def mymax(a, b):
return b if b > a else a

# 线段树维护最大子段和
tree = [Node(0, 0, 0, 0) for _ in range(2 << n.bit_length())]

def merge(nl, nr):
"""合并两个区间"""
return Node(
nl.sm + nr.sm,
mymax(nl.lv, nl.sm + nr.lv), # 左区间左半部分,或左边全选+右边左部分
mymax(nl.rv + nr.sm, nr.rv), # 右区间右半部分,或左边右部分+右边全选
mymax(mymax(nl.ans, nr.ans), nl.rv + nr.lv) # 左区间、右区间、或横跨
)

def initNode(val):
return Node(val, val, val, val)

def build(id, l, r):
if l == r:
tree[id] = initNode(nums[l])
else:
nxt = id << 1
mid = (l + r) >> 1
build(nxt, l, mid)
build(nxt + 1, mid + 1, r)
tree[id] = merge(tree[nxt], tree[nxt + 1])

def modify(id, l, r, pos, val):
"""单点更新:将位置 pos 的值改为 val"""
if l == r:
tree[id] = initNode(val)
else:
nxt = id << 1
mid = (l + r) >> 1
if pos <= mid:
modify(nxt, l, mid, pos, val)
else:
modify(nxt + 1, mid + 1, r, pos, val)
tree[id] = merge(tree[nxt], tree[nxt + 1])

# 构建线段树
build(1, 0, n - 1)

# 不删除任何元素的答案
ans = tree[1].ans

# 按值分组,记录每个值出现的所有下标
from collections import defaultdict
mp = defaultdict(list)
for i in range(n):
mp[nums[i]].append(i)

# 枚举删除哪种数
for val, indices in mp.items():
if len(indices) != n: # 删除后需要保证数组不为空
# 把这种数都改成 0(模拟删除)
for x in indices:
modify(1, 0, n - 1, x, 0)
# 更新答案
ans = mymax(ans, tree[1].ans)
# 恢复
for x in indices:
modify(1, 0, n - 1, x, val)

return ans
```

复杂度分析

- 时间复杂度:O(n \log n),构建线段树 O(n \log n),枚举每个不同值并更新 O(k \cdot m \cdot \log n),其中 k 是不同值的个数,m 是该值出现次数,总和为 O(n \log n)。
- 空间复杂度:O(n),线段树需要约 4n 个节点。

http://www.jsqmd.com/news/1098821/

相关文章:

  • 2026年桌面风扇类型选购要点:从四个核心部件看懂一台风
  • 羽毛球工具 App HarmonyOS 6.0 实战(02/10):ArkUI 响应式布局
  • Apache Commons Text RCE漏洞CVE-2022-42889:原理、复现与安全修复
  • 什么!翻译论文还要消耗token? 关于如何提升marker转英文文档速度,并使用skill批量翻译论文
  • 官方 API 与中转 API 选型实测指南
  • openEuler-portal-mcp智能推荐系统:如何实现100%工具推荐覆盖率
  • 广告创意提案怎么做?用多模型联动快速制作动态 Demo 提案实战与对比
  • VMware导入虚拟机失败?90%的运维人都踩过的7个隐藏陷阱及修复命令清单
  • 5大特色揭秘:ZR.Admin.NET企业级权限管理平台实战指南
  • 把 ES Repository 纳入 CMS 轨道,一套更稳的 SAP PI 内容传输治理方式
  • 羽毛球工具 App HarmonyOS 6.0 实战(03/10):本地优先数据方案
  • 从真实高可用链路看 SAP AEX local SLD 配置,别让 SLD 成为集群切换时的隐形单点
  • Kali Linux 渗透测试环境搭建:VMware 虚拟机安装配置全流程指南
  • Crypto方向 · RSA已知部分明文攻击(Coppersmith方法)
  • 浅谈C++重载、重写、重定义
  • YOLOv8知识蒸馏实战:从37%到42%mAP,无损提升轻量模型精度
  • Bebas Neue:开源字体设计的几何美学革命
  • 这门课程适合谁?
  • 紧急预警:VMware克隆未启用“Reconfigure after clone”将触发许可证异常——2024 Q3 VMware官方补丁前最后规避指南
  • C语言指针详解3
  • TVA:连接数字与物理世界的智能底座(5)
  • 工作原理:其核心是一个两步过程。
  • 防火墙Web界面配置一对一IPSec隧道:从原理到实战详解
  • Mineradio音乐播放器下载安装地址
  • 机顶盒B860AV2.1-M刷机攻略
  • 从 ABAP 后端到 AEX,Local Integration Engine 下的 Business System 配置全景
  • VR-Reversal:3D视频转2D的神奇工具,让沉浸式体验触手可及
  • AI渐进编程之四:状态机如何约束 AI 的动作?
  • WAF核心原理、部署模式与防护实战:从SQL注入到命令执行的安全防线
  • QoS详解:服务质量,如何优先保障关键业务的网络带宽