Never give up, always have hope in frontwaiting for. 

永不放弃,总有希望在前面等待。

问题描述


难度:简单


有一堆石头,每块石头的重量都是正整数。


每一回合,从中选出两块最重的石头,然后将它们一起粉碎。假设石头的重量分别为x和y,且x<=y。那么粉碎的可能结果如下:


如果x==y,那么两块石头都会被完全粉碎;

如果x!=y,那么重量为x的石头将会完全粉碎,而重量为y的石头新重量为y-x。

最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回0。


示例:


输入:[2,7,4,1,8,1]

输出:1

解释

先选出 7 和 8,得到 1,所以数组转换为 [2,4,1,1,1],

再选出 2 和 4,得到 2,所以数组转换为 [2,1,1,1],

接着是 2 和 1,得到 1,所以数组转换为 [1,1,1],

最后选出 1 和 1,得到 0,最终数组转换为 [1],这就是最后剩下那块石头的重量。



提示:


  • 1 <= stones.length <= 30
  • 1 <= stones[i] <= 1000



使用最大堆解决



这题要求每次取出最重的两块石头让他们俩相互销毁,如果重量一样则全部销毁,否则销毁之后的重量是大的减小的……,直到全部销毁,或者只剩一个石头为止。


因为每次都要取出最大的两块,如果先排序的话,销毁之后还要在重新排序,这样效率很差,我们可以使用最大堆来解决。最大堆就是堆顶元素始终是堆中所有元素中最大的,我们每次从堆中取出元素或者往堆中添加元素都会导致堆的调整,也就是堆顶元素始终是最大的,来看下代码。

 1public int lastStoneWeight(int[] stones) {
2 //最大堆,也就是元素最大的在堆顶
3 PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> b - a);
4 //把数组中的元素全部放入堆中
5 for (int num : stones)
6 pq.offer(num);
7 while (pq.size() > 1) {
8 //分别取出堆中最大的值和第二大的值
9 int largest = pq.poll();
10 int large = pq.poll();
11 //如果largest和large一样大,相当于他俩玉石俱焚了,
12 //否则就把他俩的差值放到堆中
13 if (largest > large)
14 pq.offer(largest - large);
15 }
16 //最后如果堆是空的,说明他们全部都玉石俱焚了,否则就返回
17 //堆中仅有的那个值
18 return pq.isEmpty() ? 0 : pq.poll();
19}

前面也讲过378,数据结构-7,堆,具体可以看下,堆中元素的添加删除涉及到往上调整往下调整,堆也可以看作是一棵完全二叉树,这里我随便举个例子做个视频来看一下