【leetcode题解】优先级队列

目录

最后一块石头的重量

数据流中的第 K 大元素

前K个高频单词

数据流的中位数


最后一块石头的重量

1046. 最后一块石头的重量 - 力扣(LeetCode)

解法一:暴力模拟(我自己的解法)

class Solution {
    public int lastStoneWeight(int[] s) {
        int n = s.length;
        int left = 0, right = n - 1;
        while (left < right) {
            Arrays.sort(s);
            if (right == left + 1) {
                if (s[right] == s[left])
                    return 0;
                else
                    return Math.max(s[right] - s[left], s[left] - s[right]);
            }
            if (s[right - 1] == s[right]) {
                right -= 2;
            } else {
                s[right - 1] = s[right - 1] < s[right] ? s[right] - s[right - 1] : s[right - 1] - s[right];
                right--;
            }
        }
        return s[left];
    }
}

解法二:大根堆模拟

class Solution {
    public int lastStoneWeight(int[] s) {
        // 创建大根堆
        PriorityQueue<Integer> heap = new PriorityQueue<>((a, b) -> b - a);
        // 把所有石头放入堆中
        for (int x : s) {
            heap.offer(x);
        }
        // 模拟
        while (heap.size() > 1) {
            int a = heap.poll();
            int b = heap.poll();
            if (a > b) {
                heap.offer(a - b);
            }
        }
        return heap.size() == 1 ? heap.poll() : 0;
    }
}

数据流中的第 K 大元素

703. 数据流中的第 K 大元素 - 力扣(LeetCode)

TopK问题:堆(O(nlongK));快速选择算法(O(n))

解法:用堆来解决

  1. 创建一个大小为k的堆(大根堆or小根堆)
  2. 循环:
    1. 依次进堆
    2. 判断堆的大小是否超过k,如果超过,就把堆顶删去,最后的堆顶即为所求
class KthLargest {
    // 创建一个大小为k的小根堆
    PriorityQueue<Integer> heap = new PriorityQueue<>();
    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();
    }
}

/**
 * Your KthLargest object will be instantiated and called as such:
 * KthLargest obj = new KthLargest(k, nums);
 * int param_1 = obj.add(val);
 */

前K个高频单词

692. 前K个高频单词 - 力扣(LeetCode)

解法:利用堆来解决topK问题

  1. 预处理原始字符串数组:用一个哈希表,统计每个单词出现的频次<String>和<String ,int >
  2. 创建一个大小为k的堆(频次由高到低 - 创建小根堆;频次相同,字典序由低到高 - 创建大根堆)
  3. 循环:
    1. 让元素依次进堆
    2. 判断:heap.size()>k 则删去堆顶
  4. 提取结果
class Solution {
    public List<String> topKFrequent(String[] w, int k) {
        // 统计每个单词出现的频次
        Map<String, Integer> hash = new HashMap<>();
        for (String s : w) {
            hash.put(s, hash.getOrDefault(s, 0) + 1);//
        }
        // 创建大小为k的堆
        PriorityQueue<Pair<String, Integer>> heap = new PriorityQueue<>((a, b) -> {
            return a.getValue().equals(b.getValue()) ? b.getKey().compareTo(a.getKey()) : a.getValue() - b.getValue();
        });
        // topK主逻辑:
        for (Map.Entry<String, Integer> e : hash.entrySet()) {
            heap.offer(new Pair<>(e.getKey(), e.getValue()));
            if (heap.size() > k)
                heap.poll();
        }
        // 提取结果
        List<String> ret = new ArrayList<>();
        while (!heap.isEmpty()) {
            ret.add(heap.poll().getKey());
        }
        // 逆序数组
        Collections.reverse(ret);
        return ret;
    }
}

数据流的中位数

295. 数据流的中位数 - 力扣(LeetCode)

解法一:直接sort(超时)

解法二:插入排序的思想(可能超时)

解法三:大小堆来维护数据流的中位数

分类讨论:

  1. m==n:
    1. num<=x||m==0 -> left;
    2. num>x -> right;right堆顶进入left;
  2. m>n -> m==n+1:
    1. num<=x -> left;left堆顶进入right;
    2. num>x -> right;
class MedianFinder {
    PriorityQueue<Integer> left;
    PriorityQueue<Integer> right;

    public MedianFinder() {
        left = new PriorityQueue<Integer>((a, b) -> b - a);
        right = new PriorityQueue<Integer>((a, b) -> a - b);
    }

    public void addNum(int num) {
        if (left.size() == right.size()) {
            if (left.isEmpty() || num <= left.peek())
                left.offer(num);
            else {
                right.offer(num);
                left.offer(right.poll());
            }
        } else {
            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();
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值