【力扣1046】最后一块石头的重量
前言
力扣每日一题*1046.最后一块石头的重量* 标记为简单题目,在没有看题解之前使用了自己的数组排序+插入的方法。看题解发现使用最大堆方法更简单。趁这个机会记录一下题目的解法,并学习一下最大堆的原理及概念
一、不使用最大堆的解法
10分钟写完,运行结果如下:
分析:
拿到题目一看逻辑比较简单,每次拿两个最大的石头,所以直接数组排序。 每次取最大的两个石头,在写题目两个中的逻辑:
逻辑1:两个石头相等,都粉碎(两个都删除)
逻辑2:不相等,两个石头粉碎剩下重量之差的石头(删除再插入)
逻辑1和2循环,直到剩下一个石头或者一个石头都不剩。
代码如下(示例):
class Solution {
public int lastStoneWeight(int[] stones) {
Arrays.sort(stones); //首先将数组排序
int n = stones.length;
int index = n-1; // 用来控制下标,下标后的元素看作已删除
while(index >= 1 ){ // 循环停止条件:剩下一个石头或者一个石头都不剩停止
int x = stones[index];
int y = stones[index-1];
if( x == y ) { // 逻辑1
index -= 2;
} else { //逻辑2
int temp = x-y;
int i = index - 1;
for(; i>0 && stones[i-1]>temp; i--){ //找到位置插入
stones[i] = stones[i-1];
}
stones[i] = temp;
index -= 1;
}
}
return index==0 ? stones[index] :0;
}
}
二、使用最大堆PriorityQueue解法
PriorityQueue优先队列,是可以实现最大堆,那么我们在堆中每次取的就是堆中最大的值,插入的数据也会自动帮我们插入到合适的位置。使用最大堆可以简化我们的插入代码。结果如下:
总体效率要低一些。其实总体思路还是一样排序+插入,只不过使用最大堆的话,这些操作由PriorityQueue帮我们做了。
代码如下:
class Solution {
public int lastStoneWeight(int[] stones) {
PriorityQueue<Integer> q = new PriorityQueue< >((a, b) -> b - a); //创建最大堆
for(int i: stones){
q.offer(i);
}
while(q.size() >= 2 ){
int x = q.poll();
int y = q.poll();
if( x != y ) {
q.offer(x-y);
}
}
return q.size()==0 ? 0:q.poll();
}
}
时间复杂度:O(nlogn)
空间复杂度:O(n)
三 、PriorityQueue详解
PriorityQueue优先队列是队列中的一种特殊队列。PriorityQueue里的元素是有序的,默认情况下是单调增,可以通过传入Comparator根据自己的需求来更改。我们来一起看看PriorityQueue的具体使用方法吧!
使用方法
继承图
可以看到PriorityQueue继承自Queue,具有队列的特性,所以我们可以使用Queue中的方法。例如:offer()和poll()。那么我们如何使用PriorityQueue呢?这里有一个最简单的例子:
PriorityQueue< Integer> p = new PriorityQueue< >();
p.offer(4);
p.offer(3);
p.offer(2);
System.out.println(p);
//得到的结果为:[2, 4, 3]
由此可以知道,PriorityQueue在不传入Comparator时是最小堆,第一位的值总是最小的。所以我们可以传入自己的Comparator
1 . 最大堆
PriorityQueue< Integer> p = new PriorityQueue< >(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
p.add(4);
p.add(3);
p.add(2);
System.out.println(p);
2. 其他比较方法
PriorityQueue< User> p = new PriorityQueue< >(new Comparator<User>() {
@Override
public int compare(User o1, User o2) {
return o1.age - o2.age;
}
});
p.offer(new User("Bob",23));
p.offer(new User("Andy",18));
System.out.println(p.poll().name); //Andy
System.out.println(p.poll().name); //Bob
当然传入的Comparator我们还可以使用Labda函数进行简写:
如:
PriorityQueue< Integer> p = new PriorityQueue< >((o1,o2) -> (o1-o2));
p.add(4);
p.add(3);
p.add(2);
System.out.println(p); //[2,4,3]
总结
在本题中,最大堆帮我们实现了数组的排序和有序的插入。通过本题对PriorityQueue的概念和用法有了一定的了解。