1. 题目背景与核心挑战
"Heavy Stones"是一道经典的算法题目,通常出现在编程竞赛和算法训练平台中。题目描述通常如下:给定n个石头的重量数组,每次操作可以选择两个最重的石头进行碰撞,若重量相同则两者消失,否则较重的石头重量变为两者之差。重复该操作直到剩余石头不超过1个,求最终剩余石头的重量(若无石头剩余则返回0)。
这道题看似简单,但蕴含着几个关键算法思想:
- 动态获取当前最大元素的数据结构选择
- 模拟过程的终止条件处理
- 不同规模数据下的时间复杂度考量
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解法思路分析
2.1 暴力模拟法
最直观的解法是直接模拟题目描述的过程:
python复制def lastStoneWeight(stones):
while len(stones) > 1:
stones.sort()
x, y = stones[-2], stones[-1]
stones = stones[:-2]
if x != y:
stones.append(y - x)
return stones[0] if stones else 0
这种方法每次都要重新排序,时间复杂度为O(n^2 logn),在n较大时(如10^5级别)会非常低效。
2.2 优先队列优化
更高效的解法是使用最大堆(优先队列)来维护石头重量:
python复制import heapq
def lastStoneWeight(stones):
# Python的heapq模块默认是最小堆,所以需要存储负值
heap = [-x for x in stones]
heapq.heapify(heap)
while len(heap) > 1:
y = -heapq.heappop(heap)
x = -heapq.heappop(heap)
if x != y:
heapq.heappush(heap, -(y - x))
return -heap[0] if heap else 0
时间复杂度分析:
- 建堆:O(n)
- 每次堆操作:O(logn)
- 总时间复杂度:O(nlogn)
3. 实现细节与优化技巧
3.1 堆的实现选择
不同语言中堆的实现方式有所不同:
- C++:
priority_queue默认是最大堆 - Java:
PriorityQueue默认是最小堆,需传入自定义比较器 - Python:
heapq模块只提供最小堆实现,需存储负值
3.2 边界条件处理
需要特别注意的特殊情况:
- 空输入数组
- 所有石头重量相同
- 最终恰好剩下一个石头
3.3 复杂度优化空间
对于特定约束条件(如石头重量范围有限),可以考虑计数排序的思路,将时间复杂度进一步优化到O(n + k),其中k是重量范围。
4. 测试用例设计
全面的测试用例应包含:
python复制test_cases = [
([2,7,4,1,8,1], 1), # 常规案例
([1,1], 0), # 完全消解
([1], 1), # 单个元素
([], 0), # 空输入
([10,10,10,10,10], 10), # 多个相同重量
[i for i in range(1,1001)], # 大规模数据
]
5. 同类问题扩展
"Heavy Stones"可以延伸出多个变种问题:
- 记录完整的碰撞过程
- 限制碰撞次数
- 引入石头硬度属性(碰撞后重量变化不同)
- 多堆石头碰撞问题
6. 实际应用场景
虽然题目设定看似简单,但类似思想可用于:
- 任务调度中的资源分配
- 游戏中的伤害计算系统
- 分布式系统中的负载均衡
提示:在面试中遇到此类问题时,建议先阐述暴力解法,再逐步优化,展示思维过程比直接给出最优解更重要。
7. 常见错误与调试技巧
新手容易犯的错误包括:
- 忘记处理所有石头都消解的情况
- 在每次操作后没有正确维护数据结构
- 错误计算碰撞后的新重量
调试时可以:
- 打印每次操作后的石头集合
- 验证堆的性质是否保持
- 检查边界条件的处理
8. 语言特性利用
以Python为例,可以进一步简化的写法:
python复制import heapq
def lastStoneWeight(stones):
heap = [-x for x in stones]
heapq.heapify(heap)
while len(heap) > 1 and (diff := -heapq.heappop(heap) + heapq.heappop(heap)):
heapq.heappush(heap, -diff)
return -heap[0] if heap else 0
这个版本利用了Python 3.8的海象运算符,使代码更简洁。
