【力扣1046】最后一块石头的重量 与 PriorityQueue的用法

【力扣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的概念和用法有了一定的了解。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值