C++ 优先级队列(大小根堆)OJ

目录

1、 1046. 最后一块石头的重量

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

        为什么小根堆可以解决TopK问题? 

3、 692. 前K个高频单词

4、 295. 数据流的中位数


1、 1046. 最后一块石头的重量

 思路:根据示例发现可以用大根堆(降序)模拟这个过程。

class Solution {
public:int lastStoneWeight(vector<int>& stones) {priority_queue<int> heap;for (auto s : stones)heap.push(s);while (heap.size() > 1) {int a = heap.top();heap.pop();int b = heap.top();heap.pop();if (a > b)heap.push(a - b);}return heap.size() ? heap.top() : 0;}
};

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

 思路:TopK问题使用小根堆堆解决,priority_queue(默认大根堆)的第三个参数为greater<类型>即为小根堆。

class KthLargest {
public:int _k;priority_queue<int, vector<int>, greater<int>> heap;KthLargest(int k, vector<int>& nums) {_k = k;for (auto n : nums) {heap.push(n);if (heap.size() > _k)heap.pop();}}int add(int val) {heap.push(val);if (heap.size() > _k)heap.pop();return heap.top();}
};/*** Your KthLargest object will be instantiated and called as such:* KthLargest* obj = new KthLargest(k, nums);* int param_1 = obj->add(val);*/

为什么小根堆可以解决TopK问题? 

对于设计一个找到数据流中第k大元素的类的问题,我们应该使用小根堆(Min Heap)来实现。下面解释为什么使用小根堆以及如何使用它:

  1. 为什么使用小根堆:

    • 小根堆能够保证堆顶元素是堆中最小的元素。在维护数据流中的第k大元素时,我们希望能够快速访问到第k大的元素,而不是最小的元素。通过维护一个大小为k的小根堆,堆中的元素就是数据流中最大的k个元素,而堆顶元素(最小元素)就是这k个元素中第k大的元素。
    • 当新的元素加入时,如果它大于堆顶元素,我们就将它加入堆中,并移除堆顶元素,这样堆的大小仍然保持为k。这样做可以确保堆中始终是数据流中最大的k个元素,而堆顶元素就是这些元素中最小的,即第k大的元素。
  2. 如何使用小根堆:

    • 初始化时,将数组nums中的元素加入小根堆中,如果元素数量超过k,则移除堆顶元素,以保证堆的大小为k。
    • 对于add方法,每次加入一个新元素时,先将其加入到小根堆中。如果加入后堆的大小超过k,则移除堆顶元素。然后返回堆顶元素,即为当前数据流中第k大的元素。

通过使用小根堆,我们可以高效地解决数据流中的第k大元素问题,同时保证时间复杂度和空间复杂度都在合理的范围内。

3、 692. 前K个高频单词

 思路:

  • 频次统计:首先,使用哈希表记录每个单词出现的频次。
  • 优先队列排序:利用优先队列(或小根堆)根据单词的频次和字典序排序,从而找出频次最高的前 k 个单词。

实现步骤

  1. 处理单词列表

    • 利用哈希表统计每个单词出现的次数,确保单词不会重复计数且记录了它们的频次。
  2. 使用小根堆选择前 k 大元素

    • 根据问题要求,设计比较器(cmp):
      • 频次不同:频次较少的优先(小根堆性质)。
      • 频次相同:字典序较小的优先(大根堆性质)。
    • 使用优先队列(小根堆)存储单词及其频次,保证堆的大小不超过 k
    • 将每个单词和它的频次插入到堆中,如果堆的大小超过了 k,就移除堆顶元素。
  3. 获取结果

    • 最终,堆中剩余的就是频次最高的前 k 个单词。反向遍历堆,将元素按正确的顺序存入结果列表中。
class Solution {
public: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;}};vector<string> topKFrequent(vector<string>& words, int k) {unordered_map<string,int> hash;for(auto& s:words)hash[s]++;priority_queue<PSI,vector<PSI>,cmp> heap;for(auto& psi:hash){heap.push(psi);if(heap.size()>k)heap.pop();}vector<string> ret(k);for(int i=k-1;i>=0;i--){ret[i]=heap.top().first;heap.pop();}return ret;}
};

4、 295. 数据流的中位数

实现一个动态中位数查找器

 动态数据流中位数查找是一种常见问题,可以通过聪明地运用数据结构来解决。以下是如何通过维护两个堆:一个大根堆和一个小根堆—来实现一个动态中位数查找器的步骤。

解决方法:利用两个堆

算法思路

本解法是一个关于堆数据结构的经典应用。通过将数据流平分或近似平分为两个部分:一个较小部分和一个较大部分—可以高效解决问题:

  • 较小的部分在大根堆(left)中。

  • 较大的部分在小根堆(right)中。

  • 如此设置允许我们在常数时间内获得中位数。

动态添加数据

我们需要保证left比right大1或者left等于right,这样才能算出中位数,当有新数据加入时,进行以下步骤以保持两个堆的平衡:

  1. 两个堆的大小相同 (left.size() == right.size()):

    • 若堆为空,直接将 num 放入 left 中。

    • 若 num <= left.top(),将 x 放入 left

    • 否则,先将 num 放入 right,再将 right 的堆顶元素移到 left 中。

  2. 两个堆的大小不相同 (left.size() > right.size()+1):

    • 若 num 小于或等于 left.top(),再将 left 的堆顶元素移到 right 中。

    • 否则,将 num 放入 right

查找中位数

  • 若两个堆的大小相同,中位数是两个堆顶元素的平均值。

  • 否则,中位数是 left 堆的顶元素。
class MedianFinder
{priority_queue<int> left; // 大根堆priority_queue<int, vector<int>, greater<int>> right; // 小根堆public:MedianFinder() {}void addNum(int num){// 分类讨论即可if(left.size() == right.size()) // 左右两个堆的元素个数相同{if(left.empty() || num <= left.top()) // 放 left 里面{left.push(num);}else{right.push(num);left.push(right.top());right.pop();}}else{if(num <= left.top()){left.push(num);right.push(left.top());left.pop();}else{right.push(num);}}}double findMedian(){if(left.size() == right.size()) return (left.top() + right.top()) / 2.0;else return left.top();}
};

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

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

相关文章

Hack The Box-Jab

目录 信息收集 nmap enum4linux 服务信息收集 Pidgin kerbrute hashcat 反弹shell & get user 提权 系统信息收集 端口转发 漏洞利用 get root 信息收集 nmap 端口探测┌──(root㉿ru)-[~/kali/hackthebox] └─# nmap -p- 10.10.11.4 --min-rate 10000 -oA…

Linux服务器(Debian系)包含UOS安全相关巡检shell脚本

#!/bin/bash# Define output file current_date$(date "%Y%m%d") # Gets the current date in YYYYMMDD format output_file"server_security_inspection_report_${current_date}.txt"# Empty the file initially echo > $output_file# 获取巡检时间 (…

unity学习(57)——选择角色界面--删除角色2

1.客户端添加点击按钮所触发的事件&#xff0c;在selectMenu界面中增加myDelete函数&#xff0c;当点击“删除角色”按钮时触发该函数的内容。 public void myDelete() {string message nowPlayer.id;//string m Coding<StringDTO>.encode(message);NetWorkScript.get…

8:00面试,8:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到9月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

MySQL语法分类 DQL(5)分组查询

为了更好的学习这里给出基本表数据用于查询操作 create table student (id int, name varchar(20), age int, sex varchar(5),address varchar(100),math int,english int );insert into student (id,name,age,sex,address,math,english) values (1,马云,55,男,杭州,66,78),…

【django framework】ModelSerializer+GenericAPIView接口数据流

GenericAPIView数据从序列化到最终返回响应的数据流 // 以ModelSerializergenerics.CreateAPIView为例 程序终归是为了处理数据&#xff0c;怎么处理&#xff0c;以怎样的顺序和方法去处理&#xff0c;就涉及到了具体的业务流程。当我们是用了一个牛掰的框架&#xff0c;发现原…

面向对象(C# )

面向对象&#xff08;C# &#xff09; 文章目录 面向对象&#xff08;C# &#xff09;ref 和 out传值调用和引用调用ref 和 out 的使用ref 和 out 的区别 结构体垃圾回收GC封装成员属性索引器静态成员静态类静态构造函数拓展方法运算符重载内部类和分布类 继承里氏替换继承中的…

JavaWeb06-MVC和三层架构

目录 一、MVC模式 1.概述 2.好处 二、三层架构 1.概述 三、MVC与三层架构 四、练习 一、MVC模式 1.概述 MVC是一种分层开发的模式&#xff0c;其中 M&#xff1a;Model&#xff0c;业务模型&#xff0c;处理业务 V&#xff1a; View&#xff0c;视图&#xff0c;界面展…

线性回归 quickstart

构建一元一次方程 100个&#xff08;X, y &#xff09;&#xff0c;大概是’y3x4’ import numpy as npnp.random.seed(42) # to make this code example reproducible m 100 # number of instances X 2 * np.random.rand(m, 1) # column vector y 4 3 * X np.random…

Fork - 将 GitHub 的某个特定仓库复制到自己的账户下

Fork - 将 GitHub 的某个特定仓库复制到自己的账户下 1. ForeverStrongCheng/OpenCV-tutorials2. Fork -> ForeverStrongCheng/R2CNN_Faster-RCNN_TensorflowReferences 访问仓库页面&#xff0c;点击 Fork 按钮创建自己的仓库。 Fork 是将 GitHub 的某个特定仓库复制到自己…

Qt 实现 Asterix 报文解析库

【写在前面】 最近工作中需要解析 Cat 21 和 Cat 62 的 ADS-B 数据 ( 自己的工作包含航空领域 )。 然后&#xff0c;因为整个 Asterix 协议类别非常之多&#xff0c;每个类别的版本也多&#xff0c;纯手工实现每个版本解析根本不现实 ( 然鹅公司之前的解析库就是这么做的且做的…

面试官:volatile如何保证可见性的,具体如何实现?

写在开头 在之前的几篇博文中&#xff0c;我们都提到了 volatile 关键字&#xff0c;这个单词中文释义为&#xff1a;不稳定的&#xff0c;易挥发的&#xff0c;在Java中代表变量修饰符&#xff0c;用来修饰会被不同线程访问和修改的变量&#xff0c;对于方法&#xff0c;代码…

前端之用HTML弄一个古诗词

将进酒 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>将进酒</title><h1><big>将进酒</big> 君不见黄河之水天上来</h1><table><tr><td ><img…

【逆向-快速定位关键代码】通过hook常用函数HashMap方法

一生要走多远的路程 经过多少年 才能走到终点 梦想需要多久的时间 多少血和泪 才能慢慢实现 天地间任我展翅高飞 谁说那是天真的预言 &#x1f3b5; Beyond《光辉岁月》 随着移动应用程序的普及&#xff0c;对于安全和隐私的关注也越来越高。安卓应用逆向…

【力扣白嫖日记】1934.确认率

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 1934.确认率 表&#xff1a;Signups 列名类型user_idinttime_stampdatetime User_id是该表的主键。每一行都…

JUC之Java对象内存布局

Java对象 对象在堆中的存储布局 它保存了什么 对象指向它的类元数据的指针&#xff0c;虚拟机通过这个指针来确定这个对象是哪个类的实例 对象头有多大&#xff1f;在64位系统中&#xff0c;Mark Word占了8个字节&#xff0c;类型指针占了8个字节&#xff0c;一共是16个字…

鸿蒙开发实现弹幕功能

鸿蒙开发实现弹幕功能如下&#xff1a; 弹幕轮播组件&#xff1a;BannerScroll import type { IDanMuInfoList, IDanMuInfoItem } from ../model/DanMuData //定义组件 Component export default struct BannerScroll {//Watch 用来监视状态数据的变化&#xff0c;包括&#…

git:码云仓库提交以及Spring项目创建

git&#xff1a;码云仓库提交 1 前言 码云访问稳定性优于github&#xff0c;首先准备好码云的账户&#xff1a; 官网下载GIT&#xff0c;打开git bash&#xff1a; 查看当前用户的所有GIT仓库&#xff0c;需要查看全局的配置信息&#xff0c;使用如下命令&#xff1a; git …

Navicat 面试题及答案整理,最新面试题

Navicat 在数据库管理中的主要用途有哪些&#xff1f; Navicat 是一款数据库管理工具&#xff0c;其主要用途包括&#xff1a; 1、多数据库支持&#xff1a; Navicat 支持多种数据库连接&#xff0c;包括 MySQL、Oracle、PostgreSQL、SQLite、SQL Server 等&#xff0c;方便用…

深度强化学习(五)(蒙特卡洛与自举)

深度强化学习&#xff08;五&#xff09;&#xff08;蒙特卡洛与自举&#xff09; 一.蒙特卡洛与自举 上一节介绍了多步 TD 目标。单步 TD 目标、回报是多步 TD 目标的两种特例。如下图所示, 如果设 m 1 m1 m1, 那么多步 TD 目标变成单步 T D \mathrm{TD} TD 目标。如果设…