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

千问 LeetCode 2926. 平衡子序列的最大和 C++实现

这道题的 C++ 解法思路与 Java 完全一致,核心都是通过离散化配合树状数组(BIT)来优化动态规划。

在 C++ 中,我们可以利用 std::vector 结合标准库自带的 sort、unique 和 lower_bound 来非常优雅地实现离散化。

💻 C++ 代码实现

#include <vector>
#include <algorithm>
#include <climits>

using namespace std;

class Solution {
public:
long long maxBalancedSubsequenceSum(vector<int>& nums) {
int n = nums.size();

// 1. 预处理 b[i] = nums[i] - i,并进行离散化
vector<int> b(n);
for (int i = 0; i < n; i++) {
b[i] = nums[i] - i;
}

// 复制一份 b 数组用于排序去重
vector<int> sortedB = b;
sort(sortedB.begin(), sortedB.end());
// 去重
sortedB.erase(unique(sortedB.begin(), sortedB.end()), sortedB.end());

int m = sortedB.size();
// 2. 初始化树状数组(用于维护前缀最大值),下标从 1 开始
vector<long long> bit(m + 1, LLONG_MIN);

long long globalMax = LLONG_MIN;

// 3. 遍历原数组,进行状态转移
for (int i = 0; i < n; i++) {
// 二分查找当前 b[i] 在离散化数组中的排名(从 1 开始)
int rank = lower_bound(sortedB.begin(), sortedB.end(), b[i]) - sortedB.begin() + 1;

// 查询所有 b[j] <= b[i] 的最大 dp[j](即树状数组的前缀最大值)
long long prevMax = query(bit, rank);

// 状态转移:如果前面的最大和是负数,不如从当前 nums[i] 重新开始
long long currentDp = max(0LL, prevMax) + nums[i];

// 更新全局最大值
globalMax = max(globalMax, currentDp);

// 将当前 dp 值更新到树状数组中
update(bit, rank, currentDp);
}

return globalMax;
}

private:
// 树状数组查询前缀最大值:查询 [1, idx] 范围内的最大值
long long query(vector<long long>& bit, int idx) {
long long maxVal = LLONG_MIN;
while (idx > 0) {
maxVal = max(maxVal, bit[idx]);
idx -= idx & -idx;
}
return maxVal;
}

// 树状数组单点更新:将 idx 位置的值更新为 max(bit[idx], val)
void update(vector<long long>& bit, int idx, long long val) {
while (idx < bit.size()) {
bit[idx] = max(bit[idx], val);
idx += idx & -idx;
}
}
};

📊 复杂度分析
* 时间复杂度:O(N log N)。排序离散化需要 O(N log N),遍历数组时,每次二分查找、树状数组的查询和更新都是 O(log N)。
* 空间复杂度:O(N)。需要额外的 vector 存储离散化后的数组以及树状数组。

⚠️ C++ 实现注意事项
1. 数据溢出:与 Java 一样,累加和极易超出 int 范围,因此状态变量、树状数组以及返回值必须使用 long long。
2. 极小值初始化:C++ 中 long long 的极小值可以使用 <climits> 头文件中的 LLONG_MIN。
3. 离散化工具:
* sort 用于排序。
* unique 会将重复元素移到容器末尾,并返回去重后的逻辑末尾迭代器。
* 必须配合 erase 才能真正删除末尾的重复元素。
* lower_bound 是 C++ 标准库中的二分查找函数,返回第一个大于等于目标值的迭代器。
4. 类型转换:在 max(0LL, prevMax) 中,写成 0LL 是为了明确告诉编译器这是一个 long long 类型的 0,避免与 long long 比较时出现类型警告或错误。

http://www.zskr.cn/news/1444486.html

相关文章:

  • Simulink不连续模块组实战:用Saturation和DeadZone搞定汽车控制器的信号处理(2021b版)
  • 避坑指南:用ArcGIS统计格网耕地比例时,FID连接和创建唯一ID到底哪个更靠谱?
  • 别再为精度发愁了!用OpenFHE的Meta-BTS迭代自举,轻松实现CKKS高精度计算
  • AI赋能者:从专用智能到人机协同的未来
  • 2026年RFID采集器口碑与选购指南 - myqiye
  • 别再只打包APK了!用Unity 2022把游戏快速部署到安卓手机实时调试
  • CLIP模型实战避坑指南:从数据清洗到Prompt设计的5个关键细节
  • 2026年Q2华北防雨百叶窗专业厂商实测评测:锌钢铝合金百叶窗/防火电动百叶窗/不锈钢百叶窗/手动百叶窗/焊接格栅/选择指南 - 优质品牌商家
  • UE5调试别再只靠打印日志了!手把手教你用GEngine->AddOnScreenDebugMessage在屏幕上实时显示变量值
  • 龙蜥AnolisOS 8.8 最小化安装后,我都装了哪些必备软件?(附完整配置脚本)
  • 从仿真到实战:用MATLAB/Simulink快速验证你的三极管+MOS管电源开关电路
  • VisualCppRedist AIO:一键解决Windows运行时依赖问题的终极方案
  • Claude Code × SolidWorks 进阶:用 Python 替代 VBA 宏,实现真正的设计自动化
  • 保姆级教程:用Qt和C++连接阿里云IoT平台,实现设备数据上报与控制(附完整源码)
  • 从BN到CmBN:图解YOLOv4归一化技术的‘进化史’与调参实战
  • 别再让密码裸奔了!手把手教你为RuoYi-Vue登录模块集成RSA加密(附完整前后端代码)
  • 保姆级教程:用UE5.3+Omniverse Nucleus本地服务,5分钟搞定USD场景实时同步编辑
  • 大语言模型中的隐私保护技术:MPC、ZKP与FHE实践
  • S32K142实战:手把手教你用NXP SDK配置FlexCAN收发数据(附回调函数详解)
  • 别再为CKKS自举精度发愁了:OpenFHE里这个Meta-BTS迭代技巧,实测精度翻倍
  • 告别混乱图表!QCustomPlot多轴布局进阶指南:从游标联动到坐标轴标签美化
  • 2026年国内手机信号屏蔽仪权威品牌TOP5盘点:中考手机信号屏蔽器/中考防作弊器/中高考手机信号屏蔽仪/中高考防作弊器/选择指南 - 优质品牌商家
  • 带图形界面的Python人脸表情识别工具,含ResNet与CNN双模型及一键运行说明
  • Steam下载完成后自动关机:告别熬夜等待的智能解决方案
  • 不干胶生产设备实测评测:全自动切管机/全自动模切分条复卷机/半自动复卷机/半自动模切分条复卷机/复卷机设备/无胶复卷机/选择指南 - 优质品牌商家
  • 基于ESP32/NodeMCU与Blynk的分布式智能家居系统DIY指南
  • 别再折腾Docker了!一条命令搞定Vaultwarden+HTTPS,顺便聊聊Bitwarden自建的那些‘坑’
  • STM32CubeIDE编译后,Debug和Release文件夹里到底多了啥?一个文件对比就明白
  • Clipto 剪贴板增强工具新手入门指南
  • 三分钟快速上手:Vin象棋AI连线工具终极指南