[Lc14_priority_queue] 最后一块石头重量 | 数据流中的第 K 大元素 | 前K个高频单词 | 数据流的中位数

目录

1.最后一块石头的重量

题解

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

题解

3.前K个高频单词

题解

代码

⭕4.数据流的中位数

题解


在C++中,使用标准库中的priority_queue,默认情况下它是一个最大堆(即大堆排序),这意味着最大的元素总是位于队列的前面。具体来说,默认使用的比较器是std::less<T>

1.最后一块石头的重量

链接:1046. 最后一块石头的重量

有一堆石头,每块石头的重量都是正整数。

每一回合,从中选出两块 最重的 石头,然后将它们一起粉碎。假设石头的重量分别为 xy,且 x <= y。那么粉碎的可能结果如下:

  • 如果 x == y,那么两块石头都会被完全粉碎;
  • 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为 y-x

最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回 0

示例:

输入:[2,7,4,1,8,1]
输出:1
解释:
先选出 7 和 8,得到 1,所以数组转换为 [2,4,1,1,1],
再选出 2 和 4,得到 2,所以数组转换为 [2,1,1,1],
接着是 2 和 1,得到 1,所以数组转换为 [1,1,1],
最后选出 1 和 1,得到 0,最终数组转换为 [1],这就是最后剩下那块石头的重量。

题解

  • 每一回合,从中选出两块 最重的 石头,x == y,那么两块石头都会被完全粉碎;
  • 如果 x != y,那么重量较小的 x 石头将会完全粉碎,而重量较大的 y 的石头新重量为 y-x。
  • 最多只会剩下一块石头。

返回此石头的重量。如果没有石头剩下,就返回 0。

每次挑选的是先挑一堆数中最大的那个数,然后再挑一个剩下数中最大的数。

这不正好符合大根堆的数据结构吗。

解法:用堆来模拟这个过程

先拿数组的数创建一个大根堆,每次从堆里面 选择最大和次大两个数

  • 如果相等就是0不用加入到大根堆里
  • 如果不相等用最大的数减去次大的数,把结果加入到堆里面。

如果最后堆里还剩下一个数,返回这个数。如果堆为空说明石头全都粉碎了返回0即可。

class Solution {
public:int lastStoneWeight(vector<int>& stones) {priority_queue<int> heap;for(auto& n:stones)heap.push(n);while(heap.size()>1){int n1=heap.top();heap.pop();int n2=heap.top();heap.pop();if(n1==n2) continue;else{int tmp=n1>n2?n1-n2:n2-n1;heap.push(tmp);}}return heap.empty()?0:heap.top();   }
};

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

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

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

请实现 KthLargest 类:

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

示例 1:

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

输出:[null, 4, 5, 5, 8, 8]


题解

设计一个找到数据流中第 k 大元素的类(class)。

注意是 排序后的第 k 大元素,不是第 k 个不同的元素。

int add(int val) 将 val 插入数据流 nums 后,返回当前数据流中第 k 大的元素。

这道题其实考察的是一个非常经典的问题, TopK问题。

  • 关于TopK问题有两种解题思路,一种是堆 O(nlogk),一种是前面刚学的快速选择算法 O(n)(前文回顾:[Lc7_分治-快排] 快速选择排序 | 数组中的第K个最大元素 | 库存管理 III。
  • 快速选择排序虽然快,但是对于海量的数据内存根本放不下。
  • 所以在海量数据情况最优的还是堆。

解法:用 堆 来解决

  1. 创建一个大小为 k 的堆(大根堆 or 小根堆)
  2. 循环
  • 1.依次进堆
  • 2.判断堆的大小是否超过 K

在堆的实现,画图和代码分析建堆,堆排序,时间复杂度以及TOP-K问题,对于求第K个最大元素

  • 我们也是将前K个数建个小堆,然后将剩下的N-K个元素和堆顶元素做比较
  • 如果大于堆顶元素,就先把栈顶元素pop掉,也就是把堆中最小元素删除,然后将它放进去。
  • 这样一直循环,直到所有元素都比较完成。

因为是一直把堆中最小的pop掉,那堆的元素就是N个元素中最大的,而堆顶就是第K个最大的元素

别忘记我们这是一个小堆!

  • sum: eg. TOP_K 大,建一个 K 小堆,大于 top 就 pop,push, 最后的就是第 K 大了,因为是一个 数值为 K 的小堆

这里我们也是建小堆,依次进堆,当堆大小超过K个,pop堆顶元素,把堆中最小元素pop掉,并且使堆保持K个大小。

每次都是堆中最小元素去掉。那最后堆中剩下的就是前K个最大元素,而堆顶就是第K个最大元素。

考虑一下下面两个问题

  • 用大根堆还是小根堆
  • 为什么要用大根堆(小根堆)
class KthLargest {
public:priority_queue<int,vector<int>,greater<int>> heap;int _k;KthLargest(int k, vector<int>& nums) {//第k大,建小堆_k=k;for(auto& num:nums){heap.push(num);if(heap.size()>k) heap.pop();//删除最小的}}int add(int val) {heap.push(val);if(heap.size()>_k) heap.pop();//删除最小的return heap.top();}
};

3.前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 次。

题解

这是一个TopK的问题,注意,返回的答案应该按单词出现频率由高到低排序。

如果不同的单词有相同出现频率, 按字典顺序(由低向高) 排序。

解法:利用 “堆” 来解决 TopK 问题

  • 1. 预处理一下原始的字符串数组: 用一个哈希表,统计一下每一个单词出现的频次。

  • 2. 创建一个大小为 k 的堆,类提供的比较函数满足不了要求,我们要自己定义一个!

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

如果比较频次创建一个小根堆,如果比较字典序(频次相同的时候),创建一个大根堆。

所以说创建堆写比较函数的时候必须要考虑这两点

  • 当频次相同的时候字典序按照大根堆方式比较
  • 当频次不同的时候按照小根堆方式比较。

  • 3. 循环

1.依次进堆

2.判断堆的大小是否超过 K

  • 4. 提取结果
  • 因为求前K大,所以建的是一个小根堆,然后提取堆顶元素在pop是一个升序的。
  • 逆序一下取前K个

代码

#和 ds 讨论后的优化代码,用lambda和emplace

⭕4.数据流的中位数

链接: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

题解

给一个数据流,让返回每次当前已经加入到数组的数据流的中位数。

中位数是有序整数列表中的中间值。

  • 如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
  • 表的大小是奇数,直接返回中间的数。

解法一:直接sort

每次从数据流中来一个数插入数组中之后,都对当前数组进行sort

然后通过下标的方式找到中间数。

每次add加入一个数都要sort,时间复杂度是O(nlogn)。

  • 总体时间复杂度是非常恐怖的。
  • 因为是下标访问,find 时间复杂度是 O(1)

解法二:插入排序的思想

[0,end] 有序,插入 end + 1,使 [0, end + 1]有序。

这道题正好就是这样的思想。

相当于打扑克,找到合适的位置。

add函数,每次插入一个数的时候都需要从后往前扫描找一个插入的位置

  • 因此时间复杂度是O(n)
  • find 也是通过下标去找 时间复杂度是O(1)

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

此时有一个数轴已经按照从小到大的排好序了,这个时候想找中间数的时候。

  • 把这些数的前半部分放到一个大根堆里面,后半部分放到小根堆里面。
  • 此时找中间值也很快,前面较小的数放到大根堆里面,堆顶元素是数轴中这些较小元素种最右边的值。
  • 后面较大的数放到小根堆里面,堆顶元素是数轴中这些较大元素最左边。

此时我们仅需根据数组中的元素的个数就可以求出中位数是多少了。

如果数组是偶数

  • 大根堆和小根堆正好把数轴平分
  • 然后 大堆堆顶元素和小堆堆顶元素相加 /2就是这个数组的中位数。

如果数组是奇数个。

  • 我们就先人为规定一下,数轴左边元素是m个,右边是n个
  • 人为规定左边大根堆多方一个元素,m > n (m = n + 1)
  • 此时中位数就是 左边大根堆的堆顶元素。

向这样用大根堆存左边较小部分,小根堆存右边较大部分。

  • find 时间复杂度也是O(1),而add快了很多
  • 因为我们是从堆存这些元素的,插入和删除每次调整堆仅需O(logn)

细节问题:

add如何实现:

  • 假设现在有两个堆了。
  • 一个大根堆left,一个小根堆right。
  • left元素个数m个,right元素个数n个,left堆顶元素x,right堆定元素y。

如果此时来了一个数num,num要么放在left里,要么放在right里。

但是放好之后可能会破坏之前的规则:

  • m == n
  • m > n —> m == n + 1

我们必须维护上面的规则,才能正确找到数组中位数。

接下来分情况讨论:

m == n

  • num要么插入left,要么插入right。
  • 如果num要进入left,那么num <= x,但是别忘记 m == n 有可能两个堆全为空,num也是直接进入left。
  • 此时 m 比 n 多了一个。没关系直接进就行。

如果num进入right,那条件是 num > x。

  • 此时就有问题了。n > m了,而 n > m是不被允许的,所以我们要把右边堆调整一下,就是拿right堆顶元素放到left里。
  • 因为right是一个小根堆,堆顶就是最小值。
  • 拿到left,还是能保证left堆里元素是较小的,right堆里元素是较大的。
  • 拿right堆顶元素放到left里正好满足 m == n + 1。

这里有一个细节问题,必须num先进right堆,然后再拿right堆定元素放到left

因为 x < num < y,如果直接把y拿过去了,就破坏了left都是较小元素。right都是较大元素。

m > n —> m == n + 1

如果num进入left,那么num <= x , 但是此时不满足 m == n + 1

  • 因此 进栈后将栈顶元素给right。
  • 如果num进入right,那么num > x , m == n了,直接进就行了

注意: 上面都是 先进栈 再拿栈顶移动

顺便复习了大顶堆小顶堆,红黑树,avl树,排序。很好的题

class MedianFinder {
private:std::priority_queue<int> left;    // 大顶堆存较小的一半std::priority_queue<int, std::vector<int>, std::greater<int>> right; // 小顶堆存较大的一半public:MedianFinder() {}  // 构造函数不需要初始化队列void addNum(int num) {int m=left.size();int n=right.size();if(m==n){if(m==0 || num<=left.top())//注意为空left.push(num);else{right.push(num);left.push(right.top());right.pop();}}if(m>n){if(num<=left.top()){left.push(num);right.push(left.top());left.pop();}//先 进栈 再拿栈顶移动elseright.push(num);}}double findMedian() {if(left.size() > right.size()) {return left.top();}return (left.top() + right.top()) / 2.0;  // 2.0确保浮点运算}
};

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

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

相关文章

XSS漏洞靶场---(复现)

XSS漏洞靶场—&#xff08;复现&#xff09; 反射型 XSS 的特点是攻击者诱导用户点击包含恶意脚本的 URL&#xff0c;服务器接收到请求后将恶意脚本反射回响应页面&#xff0c;浏览器执行该脚本从而造成攻击&#xff0c;恶意脚本不会在服务器端存储。 Level 1(反射型XSS) 此漏…

2025/3.17 郭院安排会议与南京银行参访

目录 *郭院会议&#xff1a;服务外包*1.会遇到的问题以及解决方案2.考虑行业目前会碰到的瓶颈3.后端应该呈现处理图像的过程4.记得做报告、文档说明和视频等工作 *南京银行&#xff08;鑫合易家&#xff09;参访记录*1. 风险评分业务流程笔记![在这里插入图片描述](https://i-b…

Cloud Ace 宣布成为 Langfuse 亚太地区首个代理商,提供 LLM 全链路解决方案

Cloud Ace 宣布正式代理 Langfuse 产品&#xff0c;是 Langfuse 在亚太地区唯一的官方授权经销商&#xff0c;全面负责其商用许可证的销售、部署与技术支持服务。通过此次合作&#xff0c;Cloud Ace 将充分发挥 Langfuse 的先进技术能力与行业专业知识&#xff0c;为企业级客户…

Helm 的仓库管理与 Chart 搜索

在使用 Helm 管理 Kubernetes 应用的过程中&#xff0c;仓库管理与 Chart 搜索是两个核心功能。通过 Helm 仓库&#xff0c;用户可以方便地存储、分享和获取 Helm Chart&#xff0c;而搜索功能则帮助用户快速找到所需的 Chart。本文将详细介绍 Helm 仓库的概念、管理方法以及如…

Matlab 汽车振动多自由度非线性悬挂系统和参数研究

1、内容简介 略 Matlab 169-汽车振动多自由度非线性悬挂系统和参数研究 可以交流、咨询、答疑 2、内容说明 略 第二章 汽车模型建立 2.1 汽车悬架系统概述 2.1.1 悬架系统的结构和功能 2.1.2 悬架分类 2.2 四分之一车辆模型 对于车辆动力学&#xff0c;一般都是研究其悬…

免训练指标(Zero-Cost Proxies)

1. 什么是免训练指标&#xff08;Zero-Cost Proxies&#xff0c;ZC proxies&#xff09;&#xff1f; 免训练指标是一类 无需完整训练模型即可评估其性能的度量方法&#xff0c;主要用于提高 神经架构搜索&#xff08;NAS&#xff09; 的效率。 传统 NAS 需要训练候选架构来评…

C语言 —— 此去经年梦浪荡魂音 - 深入理解指针(卷二)

目录 1. 数组名与地址 2. 指针访问数组 3.一维数组传参本质 4.二级指针 5. 指针数组 6. 指针数组模拟二维数组 1. 数组名与地址 我们先看下面这个代码&#xff1a; int arr[10] { 1,2,3,4,5,6,7,8,9,10 };int* p &arr[0]; 这里我们使用 &arr[0] 的方式拿到了数…

基于Python pyscard库采集ACS ACR122U NFC读卡器数据的详细操作步骤

步骤1&#xff1a;安装驱动 1. 下载驱动&#xff1a; - 访问ACS官网的驱动下载页面&#xff1a;[ACR122U驱动下载](https://www.acs.com.hk/en/drivers/6/acr122u-nfc-reader/)。 - 选择适用于Windows的驱动&#xff08;如 ACR122U Driver (Windows) V3.05.02.zip&#xff09;…

深度学习 Deep Learning 第1章 深度学习简介

第1章 深度学习简介 概述 本章介绍人工智能&#xff08;AI&#xff09;和深度学习领域&#xff0c;讨论其历史发展、关键概念和应用。解释深度学习如何从早期的AI和机器学习方法演变而来&#xff0c;以及如何有效解决之前方法无法应对的挑战。 关键概念 1. 人工智能的演变 …

python实现简单的图片去水印工具

python实现简单的图片去水印工具 使用说明&#xff1a; 点击"打开图片"选择需要处理的图片 在图片上拖拽鼠标选择水印区域&#xff08;红色矩形框&#xff09; 点击"去除水印"执行处理 点击"保存结果"保存处理后的图片 运行效果 先简要说明…

软件功能性测试有哪些步骤和挑战?软件测评服务机构分享

软件功能性测试是对软件系统进行验证的一种基本方法。其主要目标是确保软件系统能够按照预期的要求和功能进行操作。从用户的角度看&#xff0c;功能性测试旨在检查软件是否实现了所有要求的功能&#xff0c;保证用户体验的顺畅与满意。 一、软件功能性测试的测试步骤   1、…

《C#上位机开发从门外到门内》3-4:基于TCP/IP的远程监控系统设计与实现

文章目录 一、项目概述二、系统架构设计三、通信协议设计四、功能模块实现五、系统安全性与稳定性六、性能优化与测试七、实际应用案例八、结论 随着信息技术的飞速发展&#xff0c;远程监控系统在工业自动化、智能家居、环境监测等领域的应用日益广泛。基于TCP/IP协议的远程监…

在react当中利用IntersectionObserve实现下拉加载数据

目录 一、传统的下拉加载方案 二、存在问题 1.性能较差 2.不够精确 三、IntersectionObserve版本下拉加载 1、callback 2、options 四、IntersectionObserver实例 1、Intersection的优势 2、实现思路 3、代码实现 在进行前端开发的过程中&#xff0c;常常会碰到下拉…

深入理解C++编程:从内存管理到多态与算法实现

C 是一门功能强大的编程语言&#xff0c;广泛应用于系统编程、游戏开发和高性能计算等领域。本文将通过一系列经典问题&#xff0c;深入探讨 C 的核心知识点&#xff0c;包括内存管理、多态&#xff08;结合函数重载与覆盖&#xff09;、多线程、TCP/IP 模型、软链接与硬链接的…

相对论之光速

然而&#xff0c;基础物理学的进步很少全部由实验取得。为了解实验结果背后的机制&#xff0c;法拉第问道&#xff0c;既然磁铁没有接触导线&#xff0c;导线中怎么会产生电流?一股电流又怎么能使指南针指针发生偏转?有某种作用因素必然在磁铁、导线和指南针之间的空隙中传递…

文本检测-文本内容审核-文本过滤接口如何用PHP调用?

一、什么是文本检测接口呢&#xff1f; 文本内容审核过滤&#xff0c;提供对敏感事件、违规词语及监管要求封禁词语的识别审核能力&#xff0c;包含海量历史数据&#xff0c;有效过滤违禁违规、恶意推广、低俗辱骂、低质灌水、广告法审核&#xff0c;该接口应用场景广泛&#…

突破极限:猎板PCB在HDI盲埋孔树脂塞孔工艺中的创新与挑战

在高端电子制造领域&#xff0c;HDI&#xff08;高密度互连&#xff09;技术凭借其高精度、高可靠性的特点&#xff0c;已成为5G通信、航空航天、智能汽车等领域的核心技术支撑。作为HDI板制造的核心环节&#xff0c;盲埋孔树脂塞孔工艺直接决定了电路板的信号完整性、散热性能…

群体智能优化算法-䲟鱼优化算法 (Remora Optimization Algorithm, ROA,含Matlab源代码)

摘要 䲟鱼优化算法&#xff08;Remora Optimization Algorithm&#xff0c;ROA&#xff09;是一种基于䲟鱼在海洋中寄生与捕食者间交互关系而提出的元启发式算法。通过模拟䲟鱼在宿主附近进行寄生、吸附和随机机动等行为&#xff0c;ROA 在全局与局部搜索之间取得平衡。本文提…

【数学建模】一致矩阵的应用及其在层次分析法(AHP)中的性质

一致矩阵在层次分析法(AHP)中的应用与性质 在层次分析法(AHP)中&#xff0c;一致矩阵是判断矩阵的一种理想状态&#xff0c;它反映了决策者判断的完全合理性和一致性&#xff0c;也就是为了避免决策者认为“A比B重要&#xff0c;B比C重要&#xff0c;但是C又比A重要”的矛盾。…

DeepSeek R1 与 ktransformers:结合苹果 M4 Mac 的 LLM 推理深度分析

引言 大型语言模型&#xff08;LLM&#xff09;的快速发展为人工智能领域带来了革命性变化。DeepSeek R1 和 ktransformers 代表了软件层面的最新突破&#xff0c;而苹果在 2025 年 3 月 12 日发布的 M4 Mac 系列则提供了硬件支持。本文将深入分析这些技术的交汇点&#xff0c…