[LeetCode解题报告] 703. 数据流中的第K大元素
题目描述
设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。
你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。
示例
int k = 3;
int[] arr = [4,5,8,2];
KthLargest kthLargest = new KthLargest(3, arr);
kthLargest.add(3); // returns 4
kthLargest.add(5); // returns 5
kthLargest.add(10); // returns 5
kthLargest.add(9); // returns 8
kthLargest.add(4); // returns 8
说明
你可以假设 nums 的长度≥ k-1 且k ≥ 1。
算法
当提到排序后的第K大元素或者排序后的最K小元素时,并且经常伴随着数据的插入或弹出时,应该能想到利用堆这种数据结构。
本题的算法思路为:
- 目标:在KthLargest这个类中维护一个最小堆,且保证堆的大小为k。
- 初始时,堆中元素还不满k个时,我们一边将元素插入最末尾,然后一边调整堆为最小堆。
- 当堆中元素已满k个时,再有新的元素要往堆里放的时候,我们将它与堆顶作比较。如果待放入的值比堆顶大,我们将待放入的值放在堆顶,然后重新调整最小堆;如果待放入的值小于或者等于堆顶的值,就什么也不做。
- 结果:我们会惊奇地发现,堆顶存放的数就是要求的数据流中第K大元素,将其返回即可。
为了更好的示意整个过程,我将以题目描述中给的例子为例,在图上画出具体的过程:

边界条件
当然,本题的边界条件就是考虑k的值和堆中元素的个数。
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class KthLargest {
public:
vector<int> min_heap;
int _k;
KthLargest(int k, vector<int> nums) {
_k = k;
for(int i = 0; i < _k && i < nums.size(); i++)
{
min_heap.push_back(nums[i]);
PercUp(i);
}
for (int i = _k; i < nums.size(); i++)
adjust(nums[i]);
}
int add(int val) {
// 边界条件,即堆中还未满k个元素
if (min_heap.size() < _k)
{
min_heap.push_back(val);
PercUp(min_heap.size()-1);
}
else
adjust(val);
return min_heap[0];
}
void adjust(int x)
{
/*** 本函数用于比较待插入的元素x与堆顶的值大小,以便确认是否替换堆顶并调整最小堆 ***/
// 堆顶元素更大,直接返回
if (x <= min_heap[0])
return;
// 替换并调整的函数接口
PercDown(x);
}
void PercUp(int p)
{
/*** 本函数意在将行插入在末尾的元素调整至合适的位置以维护整个堆是最小堆 ***/
int father, child = p;
int X = min_heap[child];
while (child != 0)
{
father = (child - 1) / 2;
// 与父节点比较
if (min_heap[father] <= X)
break;
min_heap[child] = min_heap[father];
child = father;
}
min_heap[child] = X;
}
void PercDown(int X)
{
/*** 本函数将新替换进来的堆顶元素找到一个合适的位置存放以维持整个堆是最小堆***/
int father = 0;
while (2*father+1 < _k)
{
int child = 2 * father + 1;
// 找两个字节点中比较小的那个
if (child + 1 < _k && min_heap[child] > min_heap[child+1])
child++;
// 与子节点比较
if (min_heap[child] >= X)
break;
min_heap[father] = min_heap[child];
father = child;
}
min_heap[father] = X;
}
};
int main()
{
vector<int> nums = {4, 5, 8, 2};
KthLargest kth(3, nums);
cout << kth.add(3) << endl; // returns 4
cout << kth.add(5) << endl; // returns 5
cout << kth.add(10) << endl; // returns 5
cout << kth.add(9) << endl; // returns 8
cout << kth.add(4) << endl; // returns 8
return 0;
}
最后
其实c++中的stl有定义一个容器-优先队列,它的本质是堆实现的。直接利用容器的话,也不用自己写堆的调整算法了,但是堆排序作为一个比较基础的排序算法,多写几遍掌握原理还是比较有益处的。堆排序的调整算法在另一篇博文https://www.cnblogs.com/shayue/p/10426127.html中。
[LeetCode解题报告] 703. 数据流中的第K大元素的更多相关文章
- Java实现 LeetCode 703 数据流中的第K大元素(先序队列)
703. 数据流中的第K大元素 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组n ...
- Leetcode 703. 数据流中的第K大元素
1.题目要求 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器, ...
- java优先级队列的使用 leecode.703.数据流中的第K大元素
//设计一个找到数据流中第K大元素的类(class). //注意是排序后的第K大元素,不是第K个不同的元素. class KthLargest { private PriorityQueue<I ...
- 703. 数据流中的第 K 大元素
设计一个找到数据流中第 K 大元素的类(class).注意是排序后的第 K 大元素,不是第 K 个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组 nums 的构造器, ...
- leetcode 703数据流中的第K大元素
这里思路是堆排序,而且是小根堆.C++中包含在头文件<queue>的priority_queue本质就是堆排序实现的.其中priority_queue函数原型是 priority_queu ...
- 【Leetcode堆】数据流中的第K大元素(703)
题目 设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数 ...
- Leetcode 703题数据流中的第K大元素(Kth Largest Element in a Stream)Java语言求解
题目链接 https://leetcode-cn.com/problems/kth-largest-element-in-a-stream/ 题目内容 设计一个找到数据流中第K大元素的类(class) ...
- [Swift]LeetCode703. 数据流中的第K大元素 | Kth Largest Element in a Stream
Design a class to find the kth largest element in a stream. Note that it is the kth largest element ...
- 数据流中的第k大元素的golang实现
设计一个找到数据流中第K大元素的类(class).注意是排序后的第K大元素,不是第K个不同的元素. 你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中 ...
随机推荐
- linux debian 9 / centos 7配置postgresSQL数据库
#读者注意:本文可以选择不看解释,直接执行每段的0中的代码 (〇):一些概念(可以跳过直接使用(一)0的代码) 1. 客户端:psql.postgreSQL的命令行客户端程序,在终端输入psql进入p ...
- 使用Maven搭建SpringMVC
1.创建Maven Project 注意选择webapp 2.添加Maven依赖 <project xmlns="http://maven.apache.org/POM/4.0.0&q ...
- C#中 property 与 attribute的区别
说的通俗些Attribute是类,不过是一类比较特殊的类,Attribute必须写在一对方括号中,用来处理.NET中多种问题:序列化.程序的安全特征等等,在.NET中的作用非同凡响 Attribute ...
- ABP框架系列之二十四:(Email-Sending-EF-电子邮件发送)
Introduction Email sending is a pretty common task for almost every application. ASP.NET Boilerplate ...
- windows下安装QT并与visual studio 2017搭建开发环境
1.环境搭建 这里并不是说qt必须要和visual studio结合使用,不过用习惯了visual studio开发,继续使用可节省开发时间,并大大提供便利性. 关于安装过程这里不再详细赘述,软件下载 ...
- http响应头里没有或者有content-length的几种可能性
对于http的请求返回结果要进行内容的长度校验主要有两种方式,二者互斥使用 1.客户端在http头(head)加Connection:keep-alive时,服务器的response是Transfer ...
- open:在终端打开文件|应用程序等
1. 需求&解决方案 打开文件 或url(用默认应用程序): $ open fileName 打开文件 或url(用指定应用程序): $ open -a appName fileName ## ...
- apk文件md5校验之用好压对下载服务器测试[测试篇]
往往稍微有点规模的公司,都会有一个独立下载服务器,那么,我还是简单说一下下载服务器的原理吧,首先后台上传文件或软件,然后web服务器通过定时脚本检测,如有变化,则将文件同步出去到下载服务器,源站数据库 ...
- Web开发经验谈之F12开发者工具/Web调试[利刃篇]
引语:如今的整个Web开发行业甚至说整个软件开发行业,已经相当成熟,基本上已经很少找不到没有前人做过的东西了,或者换句话说,你想要实现的功能,你总能在某个地方搜索到答案,关键是你有没有这个时间精力去搜 ...
- linux下应用程序性能剖分神器gprofiler-tools-安装和使用
最近在摆弄算法的的优化,需要剖分一下算法的瓶颈,就找了一些代码剖分工具,其中 gprofileer-tools是很不错的工具,gperftools时google开源的一款C++性能分析分析工具,git ...