堆的OJ题

news2024/11/25 14:50:17

       🔥🔥 欢迎来到小林的博客!!
      🛰️博客主页:✈️林 子
      🛰️博客专栏:✈️ 小林的算法笔记
      🛰️社区 :✈️ 进步学堂
      🛰️欢迎关注:👍点赞🙌收藏✍️留言

目录

  • 703. 数据流中的第 K 大元素
  • 692. 前K个高频单词
  • 295. 数据流的中位数

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

题目链接:703. 数据流中的第 K 大元素

题目描述:

设计一个找到数据流中第 k 大元素的类(class)。注意是排序后的第 k 大元素,不是第 k 个不同的元素。

请实现 KthLargest 类:

  • KthLargest(int k, int[] nums) 使用整数 k 和整数流 nums 初始化对象。
  • int add(int val)val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。

示例:

输入:
["KthLargest", "add", "add", "add", "add", "add"]
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]
输出:
[null, 4, 5, 5, 8, 8]

解释:
KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]);
kthLargest.add(3);   // return 4
kthLargest.add(5);   // return 5
kthLargest.add(10);  // return 5
kthLargest.add(9);   // return 8
kthLargest.add(4);   // return 8

提示:

  • 1 <= k <= 104
  • 0 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • -104 <= val <= 104
  • 最多调用 add 方法 104
  • 题目数据保证,在查找第 k 大元素时,数组中至少有 k 个元素

解题思路: 这一题是典型的topK问题,第K大我们可以建小堆。第K小我们可以建大堆。为什么要这样呢?因为建小堆的话,我们的堆顶就是最小的。我Top一个后,新的堆顶就是倒数第二小的。当我们的堆只有的元素只有K个的时候。那么堆顶的元素就是 nums.size - k小的。反过来就是第K大的。nums这里指的是整个数组。

假设整个数组的大小为 7 , k 为6。 那么当堆的大小为6时,堆顶的元素就是 nums.size - 1(nums.size - heap.size)。也就是第6大的数。所以,TOPK问题找第K大建小堆,找第K小建大堆,我们要反着来。虽然正着来也可以解决单纯的topK问题,但是这一题是有add操作的,如果正着来。那么前面pop掉最大的数据就丢失了。而最小的数据却没有关系,因为小堆存的是最大的K个数。堆顶是最大K个数中最小的一个。

在这里插入图片描述

所以这一题我们可以建一个小堆。然后把nums所有的数push进去,最后再把堆pop到K的大小。而每次add就push一次,再pop一次,即可维持堆的大小为K。

代码:

class KthLargest {
public:
    priority_queue<int,vector<int>,greater<int>> _min_heap;
    int _k;
    KthLargest(int k, vector<int>& nums) {
        _k = k ;
        for(auto& n : nums)
            _min_heap.push(n); 
        while(_min_heap.size() > k) _min_heap.pop();
    }
    
    int add(int val) {
        _min_heap.push(val);
        if(_min_heap.size() > _k) _min_heap.pop();
        return _min_heap.top();
    }
};

运行结果:

在这里插入图片描述

692. 前K个高频单词

题目链接: 692. 前K个高频单词

题目描述:

给定一个单词列表 words 和一个整数 k ,返回前 k 个出现次数最多的单词。

返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率, 按字典顺序 排序。

示例 1:

输入: words = ["i", "love", "leetcode", "i", "love", "coding"], k = 2
输出: ["i", "love"]
解析: "i" 和 "love" 为出现次数最多的两个单词,均为2次。
    注意,按字母顺序 "i" 在 "love" 之前。

示例 2:

输入: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4
输出: ["the", "is", "sunny", "day"]
解析: "the", "is", "sunny" 和 "day" 是出现次数最多的四个单词,
    出现次数依次为 4, 3, 2 和 1 次。

注意:

  • 1 <= words.length <= 500
  • 1 <= words[i] <= 10
  • words[i] 由小写英文字母组成。
  • k 的取值范围是 [1, **不同** words[i] 的数量]

**进阶:**尝试以 O(n log k) 时间复杂度和 O(n) 空间复杂度解决。

解题思路:

首先这一题有2个关键点,第一点是按频次比较。第二点是频次相同时,按字母序排序。所以这里我们要一个哈希表来统治所有字符串出现的次数。然后再把哈希表的这一对key,value值入堆,而堆的大小也和上题一样设置为K个。因为频次取前K个,所以我们对频次用小根堆排。但是频次相同的字符串又要按字母序排,所以对字母序排序我们又要用大堆。

比如第一个用例。我们用堆排好序是这样的。频次用小根堆排,而频次相同,我们则按大根堆对string排。

在这里插入图片描述

而因为我们的K为2,所以堆的大小只能是2。最后变成这样。

在这里插入图片描述

而此时我TOP得到的是字母序较大的值,所以我们在把堆的值填入返回的string数组时需要倒着填,因为小的要放在前面。

要实现这种排序,我们需要自己写一个cmp函数,作为priority_queue的第三个模板参数。

代码:

class Solution {
    typedef pair<string,int> PSI; 

    //排序的仿函数
    struct cmp
    {
        bool operator()(const PSI& a ,const PSI& b)
        {
            if(a.second == b.second)
            {
                //频次相同,用大根堆排
                return a.first < b.first;  //小的放下面
            }
            return a.second > b.second; //小根堆排,大的放下面
        }
    };

public:
    vector<string> topKFrequent(vector<string>& words, int k) {
        unordered_map<string,int> map; 
        //1.统计所有字符出现次数
        for(auto& word : words) map[word]++; 

        //2.将哈希表所有元素入堆
        priority_queue<PSI,vector<PSI>,cmp> heap; 
        for(auto& it : map) heap.push({it.first,it.second}); 
        //堆的大小只能为k 
        while(heap.size() > k) heap.pop(); 

        //将堆的元素逆序放到ret数组中
        vector<string> ret(k); 
        for(int i = k - 1; i >= 0 ; i--)
        {
            //将堆顶字符串放在数组的尾部,逆序放
            ret[i] = heap.top().first;
            heap.pop();
        }
        return ret;
    }
};

运行结果:

在这里插入图片描述

295. 数据流的中位数

题目链接:[295. 数据流的中位数

题目描述:

中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。

  • 例如 arr = [2,3,4] 的中位数是 3
  • 例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5

实现 MedianFinder 类:

  • MedianFinder() 初始化 MedianFinder 对象。
  • void addNum(int num) 将数据流中的整数 num 添加到数据结构中。
  • double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。

示例 1:

输入
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
输出
[null, null, null, 1.5, null, 2.0]

解释
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1);    // arr = [1]
medianFinder.addNum(2);    // arr = [1, 2]
medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2)
medianFinder.addNum(3);    // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0

提示:

  • -105 <= num <= 105
  • 在调用 findMedian 之前,数据结构中至少有一个元素
  • 最多 5 * 104 次调用 addNumfindMedian

解题思路:

题目是找中位数,那么我们可以用2个堆。一个大堆,一个小端。大于中位数的值放小堆里面,小于等于中位数的值放大堆里面。我们只需要保证两个堆的大小相等,或者大堆的大小比小堆大1。每当一次add操作时,我们先判断两个堆大小是否相等。如果相等,则说明要往大堆push数据,那么我们先把num放进小堆,再取小堆的堆顶放入大堆,这样大堆的长度就+1了。如果不相等,说明大堆的大小比小堆大1,那么我们要往小堆push数据,所以我们先把num放进大堆,再取大堆的堆顶放入小堆。

在这里插入图片描述

代码:

class MedianFinder {
public:
    priority_queue<int,vector<int>,greater<int>> _less_heap;//小堆
    priority_queue<int,vector<int>,less<int>> _greater_heap;//大堆

    MedianFinder() {

    }
    
    void addNum(int num) {
        if(_greater_heap.size() == 0)
        {
            //第一次插入,直接入大堆
            _greater_heap.push(num); 
            return; 
        }
        //其他次插入,判断俩个堆的大小
        if(_greater_heap.size() == _less_heap.size())
        {
            //两个堆的大小相等,则放进大堆,不过需要先把num放进小堆,取小堆的堆顶放入大堆
            _less_heap.push(num);
            int top = _less_heap.top();
            _less_heap.pop();
            _greater_heap.push(top); 
        }else 
        {
            //两个堆大小不相等,则说明大堆多一个,把num放进大堆,取大堆的堆顶放入小堆,俩个堆的大小则平衡
            _greater_heap.push(num); 
            int top = _greater_heap.top();
            _greater_heap.pop();
            _less_heap.push(top);
        }
    }
    
    double findMedian() {
        //如果俩个堆大小相等,返回堆顶和 /2 ,反之返回大堆堆顶
        if(_less_heap.size() == _greater_heap.size())
            return (_less_heap.top() + _greater_heap.top()) / 2.0; 
        return _greater_heap.top();
    }
};

运行结果:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1029487.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数据结构】二叉树的·深度优先遍历(前中后序遍历)and·广度优先(层序遍历)

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

2023最新Nmap安装和使用详解,超详细教程

【点击文章末尾卡片&#xff0c;先领资料再阅读哦~】&#x1f447; 文章目录 【点击文章末尾卡片&#xff0c;先领资料再阅读哦~】&#x1f447; Nmap概述功能概述运行方式 Nmap安装Nmap参数详解目标说明主机发现端口扫描端口说明和扫描顺序服务与版本探测脚本扫描操作系统探测…

C++输入流和输出流介绍

C 又可以称为“带类的 C”&#xff0c;即可以理解为 C 是 C 语言的基础上增加了面向对象&#xff08;类和对象&#xff09;。在此基础上&#xff0c;学过 C 语言的读者应该知道&#xff0c;它有一整套完成数据读写&#xff08;I/O&#xff09;的解决方案&#xff1a; 使用 scan…

DAZ To UMA⭐二.设置DAZ导出的变形内容 和 获取模型纹理贴图位置

文章目录 🟩 设置DAZ导出的内容1️⃣ 找到要导出的参数名称2️⃣ 打开导出面板3️⃣ 设置导出规则举例 : 导出身体Assets🟦 获取模型纹理贴图🟩 设置DAZ导出的内容 设置参数有两个目的: DAZ可以进行模型的参数调整,例如胖瘦等等,那如何将这些调整后的数值一起导出到FBX中…

Window通过VMWare搭建Linux集群后,将虚拟机暴露到宿主机局域网中,实现个人服务器搭建

目录 一、目的二、实现的方法 2.1 保证VMnet8为NAT模式2.2 获取虚拟机IP后&#xff0c;与宿主机进行端口绑定2.3 查看宿主机端口配置是否生效2.4 宿主机的端口准入规则设置2.5 效果 一、目的 解决宿主机通过VMware WorkStation安装了虚拟机后&#xff0c;宿主机所在的局域网…

A股风格因子看板 (2023.09 第07期)

该因子看板跟踪A股风格因子&#xff0c;该因子主要解释沪深两市的市场收益、刻画市场风格趋势的系列风格因子&#xff0c;用以分析市场风格切换、组合风格景露等。 今日为该因子跟踪第7期&#xff0c;指数组合数据截止日2023-08-31&#xff0c;要点如下 近1年A股风格因子收益走…

开源日报 0821:帮你修复老旧照片

这篇文章总结了几个开源项目的特点和优势。其中包括了 Python 资源列表、金融研究工具、动画精灵程序、游戏和旧照片修复项目等。这些项目提供了丰富的功能和技术支持&#xff0c;用户可以根据自己的需求进行定制和改进。总的来说&#xff0c;这些开源项目为开发者和用户提供了…

在如今内卷严重的背景下,程序员该如何提高自己的收入,享受美好人生?

无论是当今程序员行业&#xff0c;还是各行各业&#xff0c;内卷都非常严重&#xff0c;好多人都处于了一种卷又卷不过&#xff0c;躺又躺不平的境地&#xff0c;十分的难受&#xff0c;那么作为一个程序员而言&#xff0c;该如何在这样的境地下提高自己的收入&#xff0c;享受…

动力节点老杜JavaWeb笔记(全)

Servlet 关于系统架构 系统架构包括什么形式&#xff1f; C/S架构B/S架构 C/S架构&#xff1f; Client / Server&#xff08;客户端 / 服务器&#xff09;C/S架构的软件或者说系统有哪些呢&#xff1f; QQ&#xff08;先去腾讯官网下载一个QQ软件&#xff0c;几十MB&#xff…

Innodb底层原理与Mysql日志机制

MySQL内部组件结构 Server层 主要包括连接器、词法分析器、优化器、执行器等&#xff0c;涵盖 MySQL 的大多数核心服务功能&#xff0c;以及所有的内置函数&#xff08;如日期、时间、数学和加密函数等&#xff09;&#xff0c;所有跨存储引擎的功能都在这一层实现&#xff0c…

1536. 排布二进制网格的最少交换次数;754. 到达终点数字;1106. 解析布尔表达式

1536. 排布二进制网格的最少交换次数 核心思想&#xff1a;贪心。枚举每一行&#xff0c;然后去找离这行最近的满足要求的那一行。我们用j保存每一行的最后一个1&#xff0c;那么尾部的0个数为n-1-j&#xff0c;每一行需要的0个数为n-i-1&#xff0c;所以得出结论 i > j。然…

asp.net网站的建立及运行

点击创建新项目 在输入框中输入asp.net&#xff0c;并选择图中的 点击下一步 点击创建 然后&#xff0c;右键&#xff0c;添加&#xff0c;新建项 选择web窗体 点击添加 点击视图&#xff0c;工具箱 选择一个label&#xff0c;记住这个id 空白处右键&#xff0c;查看代码 添…

usmile F10 系列数字牙刷:数字化刷牙体验的新巅峰

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页: &#x1f405;&#x1f43e;猫头虎的博客&#x1f390;《面试题大全专栏》 &#x1f995; 文章图文并茂&#x1f996…

51单片机4【玩转开发板】

1.开发板完全介绍 1.配件 2.开发板主板及板载原件 1.单片机 &#xff08;1&#xff09;注意不要装反了&#xff0c;凹槽的一面向上是正的 &#xff08;2&#xff09;不要再开电的时候取下或者装上。 2.单片机工作必备的外围电路 1.晶振 2.复位电路 3.电源供电电路 4.USB下载…

NLP文本生成全解析:从传统方法到预训练完整介绍

目录 1. 引言1.1 文本生成的定义和作用1.2 自然语言处理技术在文本生成领域的使用 2 传统方法 - 基于统计的方法2.1.1 N-gram模型2.1.2 平滑技术 3. 传统方法 - 基于模板的生成3.1 定义与特点3.2 动态模板 4. 神经网络方法 - 长短时记忆网络(LSTM)LSTM的核心概念PyTorch中的LST…

漫画 | 两年,我学会了所有的编程语言!

本文想要探讨的一个话题是&#xff1a;作为一个程序员&#xff0c;如何看待这么多的编程语言&#xff1f;是不是要学习&#xff1f;该怎么学习&#xff1f;其实很多人都有这样的体会&#xff0c;当你学会了一门语言以后&#xff0c;再去学习新的语言&#xff0c;难度会大大降低…

音乐随行,公网畅享,群辉Audiostation给你带来听歌新体验!

文章目录 本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是本教程使用环境&#xff1a;1 群晖系统安装audiostation套件2 下载移动端app3 内网穿透&#xff0c;映射至公网 很多老铁想在上班路上听点喜欢的歌或者相声解解闷儿&#xff0c;于是打开手…

10分钟设置免费海外远程桌面

前言 本教程将向您介绍如何使用 Amazon Lightsail 服务的免费套餐轻松搭建属于您的远程桌面。依托于 Amazon 全球可用区&#xff0c;您可以在世界各地搭建符合您配置需求的远程桌面。 本教程需要先拥有亚马逊云科技海外账户。现在注册亚马逊云科技账户可以享受12个月免费套餐…

基于springboot广场舞团系统springboot16

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

云服务器ECS_云主机_服务器托管_计算-阿里云

阿里云服务器是什么&#xff1f;云服务器ECS是一种安全可靠、弹性可伸缩的云计算服务&#xff0c;云服务器可以降低IT成本提升运维效率&#xff0c;免去企业或个人前期采购IT硬件的成本&#xff0c;阿里云服务器让用户像使用水、电、天然气等公共资源一样便捷、高效地使用服务器…