发布时间:2026/7/27 10:17:26
堆结构实现石头粉碎算法及其工程应用 1. 问题背景与核心思路这个问题源自经典的算法面试题有一堆石头每块石头的重量都是正整数。每次从中选出两块最重的石头进行粉碎如果重量相同则完全消失否则剩下两块石头重量之差的绝对值。重复这个过程直到只剩一块石头或没有石头返回最后剩下的石头重量。这个场景在实际工程中有多种应用场景比如负载均衡中服务器的动态权重调整游戏开发中道具合成系统的实现资源调度中的任务优先级处理2. 数据结构选型分析2.1 为什么选择堆结构堆优先队列是这个问题的理想选择原因在于每次操作都需要获取当前最大的两个元素插入新元素后需要保持有序性时间复杂度要求高效O(log n)的插入和删除相比其他数据结构数组排序每次操作后需要重新排序O(n log n)时间复杂度链表查找最大元素需要O(n)时间平衡二叉搜索树实现复杂杀鸡用牛刀2.2 C中的堆实现选择C标准库提供了几种优先队列实现方式// 方式1使用priority_queue最简洁 priority_queueint max_heap; // 方式2使用make_heap系列函数更灵活 vectorint heap; make_heap(heap.begin(), heap.end()); // 方式3使用multiset支持重复元素 multisetint, greaterint sorted_set;推荐使用priority_queue因为接口简洁明了底层默认使用vector实现效率有保障不需要手动维护堆属性3. 完整算法实现3.1 基础版本实现#include queue #include vector using namespace std; int lastStoneWeight(vectorint stones) { priority_queueint heap(stones.begin(), stones.end()); while (heap.size() 1) { int y heap.top(); heap.pop(); int x heap.top(); heap.pop(); if (y x) { heap.push(y - x); } // 相等时两者都消失不做操作 } return heap.empty() ? 0 : heap.top(); }3.2 优化版本实现针对可能的问题进行优化int lastStoneWeightOptimized(vectorint stones) { // 提前处理边界情况 if (stones.empty()) return 0; if (stones.size() 1) return stones[0]; // 使用移动语义避免拷贝 priority_queueint heap; for (int stone : stones) { heap.push(std::move(stone)); } while (heap.size() 1) { int y heap.top(); heap.pop(); int x heap.top(); heap.pop(); int diff y - x; if (diff 0) { // 减少不必要的push操作 if (!heap.empty() diff heap.top()) { // 如果新石头不是最大的可以先处理更大的 heap.push(diff); } else { // 否则可以直接处理 y diff; heap.push(y); continue; } } } return heap.empty() ? 0 : heap.top(); }4. 复杂度分析与性能考量4.1 时间复杂度设初始石头数量为n建堆O(n)每次操作2次pop(O(log n)) 可能的1次push(O(log n))最坏情况下需要n-1次操作总复杂度O(n log n)4.2 空间复杂度额外空间O(n)用于存储堆可以原地建堆优化到O(1)但会破坏输入数据4.3 性能优化技巧批量操作当剩余石头较多时可以一次性处理多个碰撞提前终止当堆顶元素为0时可以提前结束内存预分配预先reserve足够空间避免vector扩容并行处理对于大规模数据可以考虑并行建堆5. 边界条件与异常处理5.1 常见边界情况空输入应返回0单元素输入直接返回该元素所有石头重量相同应返回0大数情况注意整数溢出问题5.2 防御性编程实践int lastStoneWeightSafe(const vectorint stones) { try { // 验证输入数据 if (stones.size() 10000) { throw std::invalid_argument(Input too large); } for (int weight : stones) { if (weight 0) { throw std::invalid_argument(All weights must be positive); } } // 实际处理逻辑 return lastStoneWeightOptimized(stones); } catch (const std::exception e) { cerr Error: e.what() endl; return -1; // 或用optional/expected等更好 } }6. 实际应用扩展6.1 游戏开发中的应用在RPG游戏中可以用来实现class ItemMerger { public: void addItem(int weight) { inventory_.push(weight); } int mergeItems() { while (inventory_.size() 1) { int a inventory_.top(); inventory_.pop(); int b inventory_.top(); inventory_.pop(); int result abs(a - b); if (result 0) { inventory_.push(result); onMergeSuccess(a, b, result); } else { onMergeDisappear(a, b); } } return inventory_.empty() ? 0 : inventory_.top(); } private: priority_queueint inventory_; void onMergeSuccess(int a, int b, int result) { // 播放合成音效 // 显示特效 } void onMergeDisappear(int a, int b) { // 播放消失特效 } };6.2 分布式系统中的变种在处理分布式任务时可以扩展为struct Task { int priority; string id; // 其他元数据 bool operator(const Task other) const { return priority other.priority; } }; class TaskScheduler { public: void addTask(Task task) { queue_.push(std::move(task)); } void processTasks() { while (queue_.size() 2) { Task t1 queue_.top(); queue_.pop(); Task t2 queue_.top(); queue_.pop(); int diff t1.priority - t2.priority; if (diff 0) { t1.priority diff; queue_.push(std::move(t1)); } // 相等时两个任务都完成 } } private: priority_queueTask queue_; };7. 测试用例设计7.1 基础测试用例void testLastStoneWeight() { assert(lastStoneWeight({2,7,4,1,8,1}) 1); assert(lastStoneWeight({1,1}) 0); assert(lastStoneWeight({1}) 1); assert(lastStoneWeight({}) 0); assert(lastStoneWeight({10,10,10,10}) 0); assert(lastStoneWeight({1,3,5,7,9}) 1); }7.2 性能测试用例void testPerformance() { const int N 1000000; vectorint largeInput(N, 1); largeInput.back() 2; auto start chrono::high_resolution_clock::now(); int result lastStoneWeightOptimized(largeInput); auto end chrono::high_resolution_clock::now(); cout Result: result endl; cout Time: chrono::duration_castchrono::milliseconds(end-start).count() ms endl; }8. 常见问题与调试技巧8.1 典型错误模式忘记处理相等情况导致石头数量计算错误堆的顺序搞反默认是大顶堆需要时记得用greater边界条件遗漏空输入或单元素输入整数溢出大数相减可能产生负数8.2 调试技巧打印堆状态void printHeap(priority_queueint heap) { while (!heap.empty()) { cout heap.top() ; heap.pop(); } cout endl; }使用调试器观察g -g stone.cpp -o stone gdb ./stone break lastStoneWeight watch heap.size()单元测试框架#define CATCH_CONFIG_MAIN #include catch.hpp TEST_CASE(Last stone weight) { REQUIRE(lastStoneWeight({2,7,4,1,8,1}) 1); // 更多测试用例... }9. 算法变种与扩展思考9.1 保留所有中间结果vectorint lastStoneWeightProcess(vectorint stones) { vectorint process; priority_queueint heap(stones.begin(), stones.end()); while (heap.size() 1) { int y heap.top(); heap.pop(); int x heap.top(); heap.pop(); int diff y - x; process.push_back(diff); if (diff 0) { heap.push(diff); } } if (!heap.empty()) { process.push_back(heap.top()); } return process; }9.2 限制粉碎次数int lastStoneWeightWithLimit(vectorint stones, int k) { priority_queueint heap(stones.begin(), stones.end()); while (heap.size() 1 k-- 0) { int y heap.top(); heap.pop(); int x heap.top(); heap.pop(); if (y x) { heap.push(y - x); } } // 收集剩余所有石头 int total 0; while (!heap.empty()) { total heap.top(); heap.pop(); } return total; }9.3 多堆协作版本class MultiHeapSolution { public: void addPile(const vectorint stones) { heaps_.emplace_back(stones.begin(), stones.end()); } int compute() { // 找出所有堆顶最大的两个堆 // 处理它们的顶部元素 // 重复直到所有堆都处理完 // 实现略... } private: vectorpriority_queueint heaps_; };10. 工程实践建议API设计namespace StoneAlgorithm { int computeLastStoneWeight(spanconst int stones); int computeWithCustomComparator(spanconst int stones, functionbool(int,int) cmp); vectorint computeProcessSteps(spanconst int stones); }内存管理对于超大输入考虑使用内存映射文件可以使用自定义分配器优化priority_queue的内存使用并发处理int parallelLastStoneWeight(const vectorint stones) { // 将输入数据分片 // 每个线程处理一个子集 // 合并部分结果 // 最终处理剩余部分 }性能关键代码的优化// 使用更快的堆实现 #include boost/heap/fibonacci_heap.hpp int lastStoneWeightBoost(const vectorint stones) { boost::heap::fibonacci_heapint heap; for (int stone : stones) { heap.push(stone); } // 其余处理类似... }

相关新闻

2026/7/27 10:17:26

情感聊天机器人:大模型技术实现与商业应用

1. 情感聊天机器人的场景价值与技术适配性 情感聊天机器人作为大模型应用的切入点,其核心价值在于它完美匹配了大模型的技术特性与人类情感需求。从技术角度看,大模型的自然语言处理能力、上下文理解能力和生成多样性,恰好满足了情感交流所需…

2026/7/27 10:17:26

qmcdump:高效解码QQ音乐加密格式的完整实战指南

qmcdump:高效解码QQ音乐加密格式的完整实战指南 【免费下载链接】qmcdump 一个简单的QQ音乐解码(qmcflac/qmc0/qmc3 转 flac/mp3),仅为个人学习参考用。 项目地址: https://gitcode.com/gh_mirrors/qm/qmcdump qmcdump是一…

2026/7/27 10:17:26

意义悬置:符号闭环中的确定性替代-龍德明宇

意义悬置:符号闭环中的确定性替代 作者:龍德明宇[负主体性之顶刊论文系列六] 本文基于论文:Farquhar, S., Kossen, J., Kuhn, L., & Gal, Y. (2024). Detecting hallucinations in large language models using semantic entropy. Nature…

2026/7/27 11:12:29

文档下载困境的3种高效解决方案:kill-doc开源工具深度解析

文档下载困境的3种高效解决方案:kill-doc开源工具深度解析 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本就是为…

2026/7/27 11:12:29

如何快速掌握Palworld存档编辑:3种简单方法告别存档损坏

如何快速掌握Palworld存档编辑:3种简单方法告别存档损坏 【免费下载链接】palworld-save-tools Tools for converting Palworld .sav files to JSON and back 项目地址: https://gitcode.com/gh_mirrors/pa/palworld-save-tools 你是否曾因Palworld存档损坏而…

2026/7/27 11:12:29

Java大厂面试核心考点与实战解析

1. 互联网大厂Java面试全景解析在当前的互联网技术招聘中,Java工程师岗位的竞争尤为激烈。根据我近三年参与大厂技术面试的经验,一场标准的Java技术面试通常包含四个核心维度:语言基础(占比35%)、框架原理(…

2026/7/27 9:04:58

PDF合并与动态水印的工程化方案:2026国内免费工具实测对比

一、背景与测试方案 在实际项目交付中,PDF文件合并与版权保护水印的叠加是一个高频但容易被低估的技术需求。典型的处理链路涉及:多源PDF的文件流合并、页面级水印渲染(含透明度混合与图层叠加)、输出文件体积控制。看似简单的操作…

2026/7/27 0:01:12

xcku5p-ffvb676-2-i 设计 RoCEv2 时 constraints.xdc 配置依据核查记录

constraints.xdc 配置依据核查记录 被核查文件:fpga/vitis/xcku5p/build/constraints/constraints.xdc 目标板卡:RK-XCKU5P-F V1.2(搭载 xcku5p-ffvb676-2-i) 移植母本:fpga/pynq/rfsoc-pynq/build/constraints/constraints.xdc(NVIDIA Holoscan Sensor Bridge 参考工程)…

2026/7/27 0:01:12

TMS320C54x DSP内存映射与I/O模拟配置实战指南

1. 项目概述与核心价值在嵌入式系统开发,尤其是DSP这类资源受限、架构独特的处理器上,内存映射配置和I/O模拟是每个开发者都必须跨越的一道坎。这不仅仅是调试器里的几个菜单选项或命令行参数,它直接关系到你的程序能否在目标板上正确运行、能…

2026/7/27 3:13:33

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…