《LeetCode 1046 最后一块石头的重量 优先级队列解法》

一.题目

1046. 最后一块石头的重量 - 力扣(LeetCode)

二.思路讲解

2.1 思路讲解

本题要求不断取出最重的两块石头 进行粉碎,直到剩下最多一块石头。由于需要快速获取最大值 ,我们可以使用最大堆(大根堆)来存储所有石头的重量。

三.代码演示

cpp 复制代码
class Solution {
public:
    int lastStoneWeight(vector<int>& stones) 
    {
        priority_queue<int> heap;//创建大堆
        //把元素加入堆中
        for(const auto& x : stones)
        {
            heap.push(x);
        }    
        //一次要取两个元素
        while(heap.size() > 1)
        {
            int a = heap.top();
            heap.pop();
            int b = heap.top();
            heap.pop();
            //若不相同
            if(a != b)
                heap.push(a - b);
            //相同
            else
                heap.push(0);
        }
        return heap.top();

    }
};

四.代码讲解

一、数据结构选择

由于题目要求每次取出最重的两块石头 ,我们需要一种能够快速获取最大值 的数据结构。C++ 的 priority_queue 默认是大根堆,非常适合本题。

二、主函数 lastStoneWeight
  1. 创建最大堆priority_queue<int> heap;

  2. 将所有石头重量压入堆 :遍历 stones 数组,对每个元素执行 heap.push(x)

  3. 循环模拟粉碎过程:当堆中元素个数大于 1 时,重复以下步骤:

    • 取出堆顶(最大值)作为 a,并弹出。

    • 取出新的堆顶(次大值)作为 b,并弹出。

    • a != b,则将差值 a - b 压回堆中(注意:题目定义中 y ≥ x,这里 a 是较大值,b 是较小值,所以 a - b 非负)。

    • a == b,则两块石头完全粉碎,不产生新石头(代码中压入 0,但实际可以不压入;压入 0 不影响后续结果,但会多一次操作)。

  4. 返回结果 :循环结束后,堆中可能剩余 1 个石头,也可能为空(若所有石头均粉碎)。代码中直接 return heap.top(),当堆为空时会出错,但题目保证最后最多剩一块,且初始至少有一个石头,所以堆非空。若所有石头都粉碎,堆中会有一个 0(因为相等时压入 0),因此返回 0 正确。

三、关键细节
  • 大根堆的特性priority_queue<int> 默认是最大堆,堆顶元素是最大值,适合本题需求。

  • 取出顺序 :先取 a(最大值),再取 b(次大值),保证 a ≥ b

  • 差值计算 :直接用 a - b 得到新石头的重量(非负)。

五、流程图