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

千问 LeetCode 3915. 距离至少为 K 的交替子序列的最大和 Rust实现

这道题是 LeetCode 3915「距离至少为 K 的交替子序列的最大和」,核心思路是 DP + 值域离散化 + 树状数组(Fenwick Tree)优化,将复杂度从 O(n²) 降到 O(n log n)。

题目理解

给定数组 nums 和整数 k,选一个下标严格递增的子序列,满足:
1. 相邻选中下标之差 ≥ k
2. 选出的值严格交替(小大 或 大小 波动,不能相等)
3. 求最大和

核心思路

1. DP 状态:up[i] 表示以 nums[i] 结尾、最后一步是"递增"(前一个值 < 当前值)的最大和;down[i] 表示以 nums[i] 结尾、最后一步是"递减"的最大和
2. 转移逻辑:
- up[i] = nums[i] + max{down[j]},其中 j ≤ i-k 且 nums[j] < nums[i]
- down[i] = nums[i] + max{up[j]},其中 j ≤ i-k 且 nums[j] > nums[i]
3. 延迟激活:只有当 i ≥ k 时,才把 i-k 位置的状态加入树状数组,保证下标距离 ≥ k
4. 树状数组优化:用两棵树状数组分别维护"值小于当前值"和"值大于当前值"的最大 DP 值,查询/更新均为 O(log n)

Rust 实现

use std::cmp::max;
use std::collections::BTreeSet;

struct FenwickTree {
n: usize,
tree: Vec<i64>,
}

impl FenwickTree {
fn new(n: usize) -> Self {
FenwickTree {
n,
tree: vec![i64::MIN / 2; n + 2], // 初始化为极小值
}
}

// 单点取 max 更新
fn update(&mut self, mut idx: usize, val: i64) {
while idx <= self.n {
self.tree[idx] = max(self.tree[idx], val);
idx += idx & idx.wrapping_neg(); // idx += idx & (-idx)
}
}

// 前缀最大值查询 [1, idx]
fn query(&self, mut idx: usize) -> i64 {
let mut res = i64::MIN / 2;
while idx > 0 {
res = max(res, self.tree[idx]);
idx -= idx & idx.wrapping_neg();
}
res
}
}

impl Solution {
pub fn max_alternating_sum(nums: Vec<i32>, k: i32) -> i64 {
let n = nums.len();
let k = k as usize;

// 1. 值域离散化
let mut sorted: Vec<i32> = nums.clone();
sorted.sort();
sorted.dedup();
let m = sorted.len();

// 2. 两棵树状数组
// bit_down:维护 down 值,用于查询"值小于当前值"的最大 down
// bit_up_rev:维护 up 值(倒序坐标),用于查询"值大于当前值"的最大 up
let mut bit_down = FenwickTree::new(m);
let mut bit_up_rev = FenwickTree::new(m);

let mut up = vec![0i64; n];
let mut down = vec![0i64; n];
let mut ans = 0i64;

for i in 0..n {
// 3. 延迟激活:把 i-k 位置的状态加入树状数组
if i >= k {
let prev = i - k;
let prev_rank = sorted.binary_search(&nums[prev]).unwrap() + 1; // 1-based
bit_down.update(prev_rank, down[prev]);
bit_up_rev.update(m - prev_rank + 1, up[prev]); // 倒序映射,后缀变前缀
}

let cur_rank = sorted.binary_search(&nums[i]).unwrap() + 1; // 1-based

// 4. 状态转移
// up[i]:前一个值 < nums[i],从 bit_down 查询值域 [1, cur_rank-1] 的最大 down
let best_down = bit_down.query(cur_rank - 1);
up[i] = nums[i] as i64 + if best_down <= i64::MIN / 2 { 0 } else { best_down };

// down[i]:前一个值 > nums[i],从 bit_up_rev 查询值域 [cur_rank+1, m] 的最大 up
let best_up = bit_up_rev.query(m - cur_rank);
down[i] = nums[i] as i64 + if best_up <= i64::MIN / 2 { 0 } else { best_up };

ans = max(ans, max(up[i], down[i]));
}

ans
}
}

关键点解析

- 值域离散化:nums[i] 最大 10⁵,但实际不同值最多 n 个,离散化后压缩到 [1, m],树状数组大小可控
- 延迟激活:这是处理"下标距离 ≥ k"的关键技巧——遍历时不立即把当前状态加入树状数组,而是等 k 步后再加入,这样查询时自然只看到距离 ≥ k 的前驱状态
- 后缀查询技巧:树状数组天然支持前缀查询,要查"值大于当前值"的最大值,把排名 r 反转为 m - r + 1,就把后缀查询变成了前缀查询
- Rust 特有注意点:idx & (-idx) 在 Rust 中需要用 idx & idx.wrapping_neg() 来避免无符号整数的取负溢出问题;树状数组初始值设为 i64::MIN / 2 防止加法溢出
- 时间复杂度:O(n log n),空间 O(n)

示例验证

- nums = [5,4,2], k = 2:选下标 [0,2],值 [5,2],距离 2-0=2≥k,5>2 严格交替,得分 7 ✅
- nums = [3,5,4,2,4], k = 1:选下标 [0,1,3,4],值 [3,5,2,4],3<5>2<4 严格交替,得分 14 ✅
- nums = [5], k = 1:长度为 1 始终有效,得分 5 ✅

需要我把树状数组优化 DP 的通用模板整理出来吗?

http://www.cnnetsun.cn/news/4058019.html

相关文章:

  • 动态内存分配(Dynamic Memory Allocation)是C语言中在程序运行时(而非编译时)向操作系统申请和释放内存空间的机制
  • Windows 11升级检测全攻略:官方工具使用与硬件要求深度解析
  • ffmpeg 初始化配置及基本概念与套路
  • KKCE: 基于网站测速的HTTP/2优先级,全球300+节点-快快测
  • 【毕设作品】基于FastAPI的智能教室人脸考勤与注意力分析系统的设计与实现
  • YOLOv8 火焰烟雾检测全栈工程|2 类别 VOC/YOLO 消防数据集、PyQt5 可视化 GUI、ONNX 轻量化推理、全套训练评估曲线落地
  • 网络优化工程师实战指南:从协议原理到业务体验的全链路调优
  • 2026年武汉智慧燃气安全监管平台建设与厂商观察
  • 十分钟精通《三步擒龙》策略:全套指标解析
  • OSASK学习第3天 进入32位模式并导入C语言
  • WSL2与Docker在Windows开发环境中的集成与实践指南
  • 异音检测系统产线部署全流程:从方案设计到验收的六个阶段
  • 学工管理系统-高校学工信息管理系统 - 学工管理系统信息修改
  • Windows Server防火墙IP拦截实战:从原理到四种配置方法详解
  • Gitee开源项目创建与托管全流程指南:从零到协作
  • 华为OD机试真题 新系统 2026-08-05 C++ 实现【IPv4等长子网划分与自动分配系统】
  • Draw.io 高阶技巧:从绘图工具到架构设计与团队协作的生产力引擎
  • LoRA+ControlNet+IP-Adapter:AI绘画精准控制实战工作流详解
  • AIGC+PlantUML:用自然语言生成技术图表,重构高效文档工作流
  • SynWeaver:基于网站与轨迹协同学习的网页智能体泛化新范式
  • 基于 PlantUML 的软件系统行为建模:图表选型、描述规范与乙方交付要求
  • 从“烫手山芋”到“香饽饽”:流拍资产盘活方法论
  • 本地生活系统架构拆解:统一后台、订单索引与私有化交付
  • 80-版本列表分页与历史治理:为什么版本越多越要重视列表管理
  • 慈溪婚嫁习俗浅谈:新式婚嫁礼饰走红,金包银为什么更适合年轻人
  • 我回测了A 股10 年的”追涨停”策略,结果可能和你想的不一样
  • NVIDIA-SMI通信失败:3分钟定位驱动加载与内核兼容性问题
  • OpenClaw爬虫框架配置全景指南:从核心原理到实战调优
  • 从URL全角空格报错看开源项目错误处理与社区协作
  • 云服务器部署Web服务公网访问全攻略:安全组、防火墙与绑定配置