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,堆,具体可以看下,堆中元素的添加和删除涉及到往上调整和往下调整,堆也可以看作是一棵完全二叉树,这里我随便举个例子做个视频来看一下