码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 【LeetCode】升级打怪之路 Day 13:优先级队列的应用


    今日题目:

    • 23. 合并 K 个升序链表 | LeetCode
    • 378. 有序矩阵中第 K 小的元素 | LeetCode
    • 373. 查找和最小的 K 对数字 | LeetCode
    • 703. 数据流中的第 K 大元素 | LeetCode
    • 347. 前 K 个高频元素 | LeetCode

    目录

      • Problem 1:合并多个有序链表 【classic】
        • LC 23. 合并 K 个升序链表 ⭐⭐⭐⭐⭐
        • LC 378. 有序矩阵中第 K 小的元素
        • LC 373. 查找和最小的 K 对数字 【略有难度】
      • Problem 2:寻找第 k 个最大元素
        • LC 703. 数据流中的第 K 大元素 【classic】 ⭐⭐⭐⭐⭐
        • LC 347. 前 K 个高频元素 【easy】

    优先级队列的特色是动态排序,插入的元素可以自动维护正确的顺序。其限制就是,优先级队列的限制是只能从队头和队尾操作元素。

    一般来说,用到优先级队列的题目主要分两类:

    1. 一类是合并多个有序链表这类题
    2. 另一类是寻找第 k 个最大元素这类题

    这两类题目都是经典题型,需要理解。

    Problem 1:合并多个有序链表 【classic】

    有很多题目在使用优先级队列时,解题思路都可以归结于“合并多个有序链表”,这里先学会使用 PriorityQueue 来解决合并多个有序链表的问题,再看看有哪些变形。

    LC 23. 合并 K 个升序链表 ⭐⭐⭐⭐⭐

    23. 合并 K 个升序链表 | LeetCode

    这个题目可以用双指针法,但使用优先级队列更能解决这一大类问题。

    这种题的基本思路就是:将每个链表的头节点入队,然后开始迭代,每轮迭代中,从队列中拿出堆顶元素(即最小元素),然后把这个节点的 next 节点入队,进入下一轮迭代。直到合并结束。

    这种解题思路很巧妙地运用了各链表“升序”的特点以及优先级队列的好处。

    class Solution {
        public ListNode mergeKLists(ListNode[] lists) {
            if (lists.length == 0) {
                return null;
            }
            
            PriorityQueue<ListNode> queue = new PriorityQueue<>(lists.length, (a, b) -> (a.val - b.val));
            ListNode vHead = new ListNode();
            ListNode curr = vHead;
    
            // 将各链表的头节点放入队列中
            for (var node: lists) {
                if (node != null) {
                    queue.offer(node);
                }
            }
    
            while (!queue.isEmpty()) {
                var min = queue.poll();  // 获取当前堆中最小元素节点
                curr.next = min;
                curr = curr.next;
                if (min.next != null) {
                    queue.offer(min.next);
                }
            }
    
            return vHead.next;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    LC 378. 有序矩阵中第 K 小的元素

    378. 有序矩阵中第 K 小的元素 | LeetCode

    这个题是上面“合并 K 个升序链表”的变形题,因为矩阵的每一行都是升序的,可以将矩阵的每一行视为一个升序链表,这样解题思路就与之前的是一样了,难度不大。

    LC 373. 查找和最小的 K 对数字 【略有难度】

    373. 查找和最小的 K 对数字 | LeetCode

    一开始做这个题,没有想到如何使用 PriorityQueue,也没有将这个题转换到“合并 K 个升序链表”这个基本问题的思路上,导致出现多次提交错误。这个题目本质上还是合并 K 个升序链表的变形。

    这个题目可以这样想象将其转换为 K 个有序链表:将固定一个 nums1[i] 与 nums2 的各个元素进行相加,就可以一串升序的结果。所以每个 nums1 的元素可以按照上面这种方式得到一个链表,那么这个问题就转换为了 nums1.length 个升序链表的合并问题了。

    举例子可以参考 labuladong 的讲解:

    在这里插入图片描述

    想清楚思路之后,难度也就还行了。

    Problem 2:寻找第 k 个最大元素

    这是 PriorityQueue 的另一个经典应用。直接通过题目来看一下。

    LC 703. 数据流中的第 K 大元素 【classic】 ⭐⭐⭐⭐⭐

    703. 数据流中的第 K 大元素 | LeetCode

    这个题目是经典的利用 PriorityQueue 来寻找第 k 个最大元素的问题。

    PriorityQueue 来寻找 Top K 的方法与排序等方法的关键区别在于:只找到 Top K,不排序 Top K。

    因为如果使用排序法的话,就是对所有元素排序,然后就可以找到 top K 了,但是使用 priority queue 的话,Top K 的 K 个元素的顺序都是可以不用排出来的。

    解题思路:

    top-k

    来源:拜托,面试别再问我TopK了!!!

    这里可以得到一个经验:保持小根堆一直为 K 的元素,就可以保证这 K 个元素是一个数据流的最大的 K 的元素,因为比他们小的元素都被 pop 出去了,因为小根堆的顶端是最小元素,所以每次 pop 出去的一定是最小元素。

    代码实现:

    class KthLargest {
    
        private int k;
    
        private PriorityQueue<Integer> heap;
    
        public KthLargest(int k, int[] nums) {
            this.k = k;
            this.heap = new PriorityQueue<>(k + 1);
            for (int num: nums) {
                heap.offer(num);
                if (heap.size() > k) {
                    heap.poll();  // pop 出最小元素
                }
            }
        }
        
        public int add(int val) {
            heap.offer(val);
            while (heap.size() > k) {
                heap.poll();  // pop 出最小元素
            }
            return heap.peek();  // 堆中是最大的 K 个元素,堆顶就是这个 K 个元素中最小的那个,也就是第 K 大的元素
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    LC 347. 前 K 个高频元素 【easy】

    347. 前 K 个高频元素 | LeetCode

    循环队列的经典应用,难度不大。

  • 相关阅读:
    Npm发布自己的插件包
    数据库注入提权总结(四)
    Prompt Engineering
    uniCloud开发公众号:三、生成带参数二维码
    【管理运筹学】第 5 章 | 整数规划(4,指派问题)
    1035 Password
    华为任正非:活下来!
    Ajax中什么时候用同步,什么时候用异步?
    TensorRT开发环境搭建
    Rasa 3.1 机器学习二构建槽值对话
  • 原文地址:https://blog.csdn.net/qq_45668004/article/details/136440910
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号