首页 > 编程语言 >算法专题:优先级队列(堆)

算法专题:优先级队列(堆)

时间:2024-11-13 17:16:28浏览次数:3  
标签:优先级 队列 元素 int 算法 heap poll left

目录

1. 最后一块石头的重量

1.1 算法原理

1.2 算法代码

2. 数据流中的第 K 大元素

2.1 算法原理 

2.2 算法代码

3. 前 K 个高频单词

3.1 算法原理

3.2 算法代码

4. 数据流的中位数

4.1 算法原理

4.2 算法代码


1. 最后一块石头的重量

. - 力扣(LeetCode)

1.1 算法原理

  • 建一个大根堆, 每次取出的元素就是最大值, 每次连取两个元素, 进行抵消, 再将差值放入堆中. 
  • 当堆中的元素 <= 1 时, 就是最后一块石头的重量.

1.2 算法代码

class Solution {
    public int lastStoneWeight(int[] stones) {
        // 建大根堆
        PriorityQueue<Integer> heap = new PriorityQueue<>((n1, n2) -> n2 - n1);
        for(int x : stones) heap.offer(x);
        while(heap.size() > 1) {
            int x = heap.poll();
            int y = heap.poll();
            if(x != y) heap.offer(x - y);
        }
        return heap.isEmpty() ? 0 : heap.poll();
    }
}

2. 数据流中的第 K 大元素

. - 力扣(LeetCode)

2.1 算法原理 

Top-K 问题

1. 求第 k 个最大值 => 建小堆

  1. 理解1: 堆顶元素最小, 若有元素大于堆顶元素, 则poll出堆顶元素, 将新元素入堆. 全部元素比较完后, 堆中的元素就是最大的几个值.
  2. 理解2: (反向假设) 若建大堆, 堆顶元素是最大的, 但是堆中可能存在更小的值, 而我们无法与堆内部的元素进行比较

2. 求第 k 个最小值 => 建大堆

  1. 理解1: 堆顶元素最大, 若有元素小于堆顶元素, 则poll出堆顶元素, 将新元素入堆. 全部元素比较完后, 堆中的元素就是最小的几个值.
  2. 理解2: (反向假设) 若建小堆, 堆顶元素是最小的, 但是堆中可能存在更大的值, 而我们无法与堆内部的元素进行比较

2.2 算法代码

class KthLargest {
    PriorityQueue<Integer> queue;
    int k;
    public KthLargest(int k, int[] nums) {
        this.k = k;
        queue = new PriorityQueue<>();
        for(int x : nums) {
            queue.offer(x);
            if(queue.size() > k) queue.poll();
        }
    }
    
    public int add(int val) {
        queue.offer(val);
        if(queue.size() > k) queue.poll();
        return queue.peek();
    }
}

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

3. 前 K 个高频单词

. - 力扣(LeetCode)

3.1 算法原理

  • Top-K 问题

1. 使用哈希表, 统计每个单词出现的频率 Map<String, Integer>

2. 建堆 Pair<String, Integer>
 2.1 如果两个单词出现的频率不相同 => 根据单词的出现频率, 建小堆
 2.2 如果两个单词出现的频率相同 => 根据字典序, 建大堆

3. 循环将元素入堆, 当堆中元素大于 k 时, 将堆顶元素出堆

4. 最终, 堆中的元素就是频次出现最高的 k 个元素, 放入数组中

5. 数组逆序

3.2 算法代码

class Solution {
    public List<String> topKFrequent(String[] words, int k) {
        // 统计每个字符串出现的频次
        Map<String, Integer> hash = new HashMap<>();
        for(String str : words) {
            if(!hash.containsKey(str)) hash.put(str, 1);
            else hash.put(str, hash.get(str) + 1);
        }
        // 预处理堆
        PriorityQueue<Pair<String ,Integer>> heap = new PriorityQueue<>((p1, p2) -> {
            int n1 = p1.getValue(), n2 = p2.getValue();
            if(n1 != n2) return n1 - n2;
            else return p2.getKey().compareTo(p1.getKey()); 
        });
        // Top-K 
        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;
    }
}

4. 数据流的中位数

. - 力扣(LeetCode)

4.1 算法原理

  • 解法一: 每插入一个元素, 进行一次排序 => O(N*logN) 超时
  • 解法二: 没插入一个元素, 进行一次插入排序 => O(N) 超时
  • 解法三: 利用大小堆, 获取中位数

大堆放入有序序列的前 m 个元素, 小堆放入有序序列的后 n 个元素 (要求: m == n || m == n + 1)

此时, 大小堆的堆顶元素就是有序序列中间位置的两个元素

注意 add 时, 要添加的数据和左堆/右堆数量不匹配的问题

4.2 算法代码

class MedianFinder {
    PriorityQueue<Integer> left; 
    PriorityQueue<Integer> right;
    
    public MedianFinder() {
        // 大堆
        left = new PriorityQueue<>((a, b) -> b - a);
        // 小堆
        right = new PriorityQueue<>();
    }
    
    public void addNum(int num) {
        int m = left.size(), n = right.size();
        if(m == n) {
            if(left.isEmpty() || left.peek() >= num) left.offer(num);
            else {
                right.offer(num);
                left.offer(right.poll());
            }
        }
        if(m == n + 1) {
            if(left.peek() >= num) {
                left.offer(num);
                right.offer(left.poll());
            }else right.offer(num);
        }
    }
    
    public double findMedian() {
        int m = left.size(), n = right.size();
        if(m == n + 1) return left.peek();
        else return (left.peek() + right.peek()) / 2.0;
    }
}

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

END

标签:优先级,队列,元素,int,算法,heap,poll,left
From: https://blog.csdn.net/2401_83595513/article/details/143509530

相关文章

  • BFS 算法专题(二):BFS 解决 FloodFill 算法
    目录1.图像渲染1.1算法原理1.2算法代码2.岛屿数量2.1算法原理2.2算法代码3.岛屿的最大面积3.1算法原理3.2算法代码4.被围绕的区域4.1算法原理4.2算法代码1.图像渲染.-力扣(LeetCode)1.1算法原理在本专题之前,对于FloodFill算法,我们就已......
  • 代码随想录算法训练营第二十五天| leetcode491.递增子序列、leetcode46.全排列、leetc
    1leetcode491.递增子序列题目链接:491.非递减子序列-力扣(LeetCode)文章链接:代码随想录视频链接:回溯算法精讲,树层去重与树枝去重|LeetCode:491.递增子序列_哔哩哔哩_bilibili思路:用之前的方法,结果翻车了,好好看视频学新技能吧1.1视频后的思路真的没想到用set来去重,还是基......
  • 迪杰斯特拉算法、弗洛伊德算法和BFS(广度优先搜索)
    迪杰斯特拉算法、弗洛伊德算法和BFS(广度优先搜索)都是用于求解最短路径问题的经典算法,它们各自有不同的特点和适用场景。以下是对这三种算法的介绍、区别以及代码实现的简要概述。迪杰斯特拉算法(Dijkstra'salgorithm)介绍:迪杰斯特拉算法是一种单源最短路径算法,用于计算一个......
  • Lock Free 无锁队列的实现
    无锁队列的实现 无锁队列的实现原理一般是利用Retry-loop和CAS等原子操作。现在几乎所有的CPU指令都支持CAS的原子操作,X86下对应的是 CMPXCHG 汇编指令。例如CAS(CompareAndSwap)的实现原理:boolcompare_and_swap(int*addr,intoldval,intnewval){if(*ad......
  • 代码随想录算法训练营 | 所有可达路径
    所有可达路径文章链接:https://programmercarl.com/kamacoder/0098.所有可达路径.html#本题代码题目链接:https://kamacoder.com/problempage.php?pid=1170#include<iostream>#include<vector>usingnamespacestd;//全局路径vector<vector<int>>paths;vector<in......
  • c语言第九课,各种算法
    选择排序选择排序(从未排序列找到最值,放到排序序列的起始位置)#include<stdio.h>voidselect_sort(inta[],intn)//定义选择排序函数{  for(inti=0;i<n-1;i++)//遍历数组找到最小的元素索引,n-1是因为最后一次可以排序两个  {    intmin=i;//假......
  • 洛谷题单 算法2-2 常见优化技巧
    洛谷题单算法2-2常见优化技巧单调栈单调栈最经典的应用,就是在一个数列里寻找距离元素最近的比其大/小的元素位置。模板题,寻找每个元素右边第一个比它大的元素下标。stack<int>s;for(inti=n;i>=1;i--){while(s.size()&&a[s.top()]<=a[i])s.pop();f[i]=s.......
  • 非煤矿山算法智慧矿山一体机提升机危险区域违规闯入识别边坡监测预警系统详述
    在矿山行业中,安全始终是最为关键的议题。随着智能化技术的发展,智慧矿山一体机应运而生,它专为矿山安全监控和管理设计,集成了多种智能化功能,以提升矿山的安全监管能力和生产效率。这款设备不仅能够满足矿山场景下的视频智能化建设需求,还能够通过边缘计算技术实现对矿山安全风险的实......
  • 【算法学习】单调队列优化dp
    前言这已经是很基础很模板化的优化了,我们可以理解为用贪心的思路去掉了永远不可能用到的状态,通常用于长度固定是个区间、最大值且满足单调性的题目。如果一个选手比你小,还比你强,你就永远也打不过他了。这很残酷但这也是单调队列的思想,虽然现实情况比较多变。P3572[POI2014]PT......
  • 街面环卫算法视频分析服务器沿街晾晒智慧城管算法详解
    在城市精细化管理的背景下,智慧城管和街面秩序维护的需求日益增长。为了提高城市管理效率,确保城市秩序和市容市貌,一款集高清视频监控、智能分析与告警、数据资源共享服务于一体的智能化一体机设备应运而生。本文将详细介绍街面环卫算法视频分析服务器的功能特点以及其在智慧城管和......