1、最后一块石头的重量 - 力扣(LeetCode)
思路:
- 使用大根堆,把数据存入大根堆中
- 每次取出最大的两个,进行比较
- 相等的话就不重新入堆,不相等的话将差值重新入堆
- 代码:
public int lastStoneWeight(int[] stones) { //创建一个大根堆 PriorityQueue<Integer> heap = new PriorityQueue<>((a,b) -> b - a); //将元素都入堆 for(int x : stones){ heap.offer(x); } //判断 while(heap.size() > 1){ int a = heap.poll(); int b = heap.poll(); if(a > b){ heap.offer(a - b); } } return heap.isEmpty() ? 0 : heap.peek(); }
2、数据流中的第 K 大元素 - 力扣(LeetCode)
思路:
- 使用小根堆,,让数组的值入堆
- 判断堆的大小,大于的话就弹出堆顶,
- 代码:
class KthLargest { PriorityQueue<Integer> heap; int _k; public KthLargest(int k, int[] nums) { _k = k; heap = new PriorityQueue<>(); for(int x : nums){ heap.offer(x); if(heap.size() > _k){ heap.poll(); } } } public int add(int val) { heap.offer(val); if(heap.size() > _k){ heap.poll(); } return heap.peek(); } }
3、前K个高频单词 - 力扣(LeetCode)
思路:利用堆来解决 TopK问题
- 用一个哈希表统计一下每一个单词出现的频次
- 创建一个大小为k的堆
比较频次用:小根堆
比较字典序用:大根堆- 让元素依次进堆,如果堆的长度大于k的话,就弹出堆顶元素,再进堆,最后堆里面就是第k大的元素
- 最后提取结果,将数组逆序
- 代码:
public List<String> topKFrequent(String[] words, int k) { //1、统计每一个单词出现的频次 Map<String,Integer> hash = new HashMap<>(); for(String s : words) { hash.put(s, hash.getOrDefault(s,0)+1); } //2、创建一个大小为k的堆 PriorityQueue<Pair<String,Integer>> heap = new PriorityQueue<> ( (a,b) -> { //频次相同的话,字典序按照大根堆的方式排列 if(a.getValue().equals(b.getValue())) { return b.getKey().compareTo(a.getKey()); } return a.getValue() - b.getValue(); } ); //3、Topk的主逻辑 for(Map.Entry<String,Integer> e : hash.entrySet()) { heap.offer(new Pair<>(e.getKey(), e.getValue())); if(heap.size() > k) { heap.poll(); } } //4、提取结果 List<String> ret = new ArrayList<>(); while(!heap.isEmpty()) { ret.add(heap.poll().getKey()); } //逆序数组 Collections.reverse(ret); return ret; }
4、 数据流的中位数 - 力扣(LeetCode)
思路:
- 解法一:每次添加一个数就重新排序,找出中位数
解法二:使用插入排序
解法三:创建大小堆来维护中间值(本题解法)- 分两种情况:
- 代码:
class MedianFinder { PriorityQueue<Integer> left; PriorityQueue<Integer> right; public MedianFinder() { //大根堆 left = new PriorityQueue<>((a,b) -> b - a); //小根堆 right = new PriorityQueue<>((a,b) -> a - b); } public void addNum(int num) { //当数量一样时 if(left.size() == right.size()){ //left 堆为空或者 num小于left中最大值,直接入堆 if(left.isEmpty() || num <= left.peek()){ left.offer(num); }else{ //大于left中最大值的话就入right,再将right中的最小值入left,维持m >= n right.offer(num); left.offer(right.poll()); } }else{ //数量不一样时,看num的大小分情况讨论 if(num <= left.peek()){ left.offer(num); right.offer(left.poll()); }else{ right.offer(num); } } } public double findMedian() { if(left.size() == right.size()){ return (left.peek() + right.peek())/2.0; }else{ return left.peek(); } } }