堆结构实现石头粉碎算法及其工程应用

发布时间:2026/11/13 21:49:01

堆结构实现石头粉碎算法及其工程应用 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/11/11 16:59:49

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

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

2026/11/11 4:34:45

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

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

2026/11/12 4:47:46

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

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

2026/11/13 21:44:14

电工证在网上如何注销别怕,注销流程不难,还省下多少钱

电工证在网上如何注销别怕,注销流程不难,还省下多少钱 证书过期了不知道怎么复审延期,别慌,今天咱就来聊聊电工证在网上如何注销的问题,尤其是对河南商丘的市政公用工程从业者来说,搞清楚注销流程、复审费用和电子证书下载方法,真的能省下一笔不小的开…

2026/11/13 21:44:14

复审电工证考几内部消息曝光:考不过白交培训费?真相来了

复审电工证考几内部消息曝光:考不过白交培训费?真相来了 怕考不过白交培训费?我懂你,这年头谁不想省点钱、少走点弯路。尤其是像你这样从驻马店转岗过来的,好不容易找了个电工相关的工作,结果发现还要考个复审电工证,培训费一交就是几千块,万一考不过…

2026/11/13 21:44:14

电工证可以借人吗内部消息:工地太忙根本没时间复习考试

电工证可以借人吗内部消息:工地太忙根本没时间复习考试 工地太忙根本没时间复习考试,电工证还能借人用?我跟你们说,这事儿可真不是你想的那么简单。最近在鹤壁做建筑工的李师傅就找我问过:“我手上有个电工证,能不能借给同事用?他最近急着用证上岗,我…

2026/11/13 21:44:14

电工找工作卡在证上?大型一级高压电工证含金量你得知道

电工找工作卡在证上?大型一级高压电工证含金量你得知道 你是不是也这样,明明技术不错,但一到工地就被问:“有证吗?”没证连面试资格都没有,这种滋味谁懂?我有个朋友老李,从建筑工地转岗到电力行业,整整半年没找到合适的工作,原因就是没有大型一级高…

2026/11/13 21:39:13

山东电工证从哪考内部消息告诉你怎么复审延期

山东电工证从哪考内部消息告诉你怎么复审延期 证书过期了不知道怎么复审延期?别急,今天给你讲讲山东电工证从哪考的内部消息,还有怎么处理证书过期问题,别再被坑了。 为什么山东电工证这么重要?…

2026/11/12 20:35:13

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/13 0:01:06

办上海高压电工证良心建议:别被中介坑了,自己看这篇就够了

办上海高压电工证良心建议:别被中介坑了,自己看这篇就够了 你是不是也像我一样,第一次听说“高压电工证”这个名词,就感觉一头雾水?其实很多人都跟我一样,不知道去哪报名、怕被中介坑,结果花了冤枉钱还考不上。今天我就从一个在商丘培训过的学员角度,…

2026/11/13 0:01:06

黎里考电工证在哪里值不值得考

黎里考电工证在哪里值不值得考 之前考的证在外省能不能转过来?这是很多在外地工作、准备回老家发展的朋友最关心的问题。特别是在黎里地区,很多从事电力相关工作的朋友,都面临这样一个难题: 外省的电工证能否在本地使用?值不值得考?…

2026/11/13 0:01:06

毕节哪里考电工证 怎么报名学历不高也能上手

毕节哪里考电工证 怎么报名学历不高也能上手 你是不是也和我一样,学历不高,想着考个电工证,但又担心自己条件不够,怕报不上名?其实不然,只要符合条件,学历不高也能考电工证。今天就来聊聊【毕节哪里考电工证】这个问题,还有怎么报名,让你一步到位不…

2026/11/12 22:10:13

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/13 12:14:39

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑