面试中经常会问到的一道题目:从n个未排序的数中得到的最大的k个数,称为TopK问题。(最小的k个数做法也相似)
基于快速排序中的partition函数,时间复杂度为O(n),空间复杂度为O(1);需要改变输入;
(1)根据Partition函数得到索引值index,index前的数据均大于nums[index],index后的数据均小于nums[index]
(2)如果index = k-1,则已经划分完成;数组前k个数据即为最大的k个数
(3)如果index>k-1,begin=index+1;否则end = index-1
(4)重复(2)操作直到index = k-1
class SolutionI {
public:
/*
* 基于快排Partition函数
* 时间复杂度O(n)空间复杂度O(1)需要改变输入
*/
vector<int> getTopK(vector<int> nums, int k){
if (nums.empty() || k > nums.size() || k<=0) return {
};
vector<int> ret;
int begin = 0, end = nums.size()-1;
int idx = Partition(nums,begin,end);
while (idx != k-1){
if (idx < k-1){
begin = idx + 1;
idx = Partition(nums,begin,end);
}else{
end = idx - 1;
idx = Partition(nums,begin,end);
}
}
for (int i = 0; i < k; ++i) {
ret.push_back(nums[i]);
}
return ret;
}
// 返回索引值idx,idx前的元素均大于该处的元素值;idx后的元素均小于该处的元素值
int Partition(vector<int> &nums, int begin, int end){
if (begin > end) return begin;
int key = nums[begin]; // 取最后一个值为基准值
while (begin < end){
while (nums[end] <= key && begin < end) --end;
nums[begin] = nums[end];
while (nums[begin] > key && begin < end) ++ begin;
nums[end] = nums[begin];
}
nums[begin] = key;
return begin;
}
};
动态维护大小为k的堆,时间复杂度为O(nlogk),空间复杂度为O(k),无需改变输入;
用multiset
实现最小堆;其基于红黑树实现,查找、删除、插入时间复杂度为O(logk)
每次比较最小堆的堆顶元素(topK大元素中最小值)与当前元素,如果当前元素更大,替换该元素。
class SolutionII {
public:
/*
* 最小堆方法
* 时间复杂度O(nlogk)空间复杂度O(k)
*/
vector<int> getTopK(vector<int>& nums, int k){
if (nums.empty() || k > nums.size() || k<1) return {
};
vector<int> ret;
multiset<int, less<int>> m; // 最小堆,保存最大的K个数
multiset<int, less<int>>::iterator it;
for (int i = 0; i < nums.size(); ++i) {
if(m.size()<k){
m.insert(nums[i]);
} else{
it = m.begin();
// 如果当前值大于topK的最小元素(最小堆堆顶),替换该值
if (nums[i]> *it){
m.erase(it);
m.insert(nums[i]);
}
}
}
for (it = m.begin();it!=m.end();it++)
ret.push_back(*it);
return ret;
}
};
基于Partition的解法 | 基于堆或红黑树 | |
---|---|---|
时间复杂度 | O(n) | O(nlogk) |
是否需要修改输入数据 | 是 | 否 |
是否适用于海量数据 | 否 | 是 |
基于partition函数的平均时间复杂度更快,但是具有明显的限制,如会修改输入数组
基于堆或红黑树的方法,具有两个明显优点:(1)没有修改输入数据(2)适合海量数据的输入。由于内存大小有限,可能无法一次性将所有数据全部载入内存,这时可每次读入一个数字,再进行判断;只需要内存能够容纳k个数据即可,适用于n很大并且k很小的问题。
文章浏览阅读227次。????????关注后回复“进群”,拉你进程序员交流群????????来自公众号:沉默王二综合自知乎:https://www.zhihu.com/question/315887668大家好,今天分享的这篇:“中国的铁路订票系统在世界上属于什么水平?”我们来看看知友们都是如何评价我国铁路订票系统的——也就是大名鼎鼎的 12306。会非常有意思。先来看看这个 1.8 万赞的,我觉得说得非常有道理..._目前国内外对火车票订票系统设计研究水平
文章浏览阅读701次。1.邻接矩阵用矩阵表示顶点与顶点间边的关系(是否有边)#define INFINITY INT_MAX#define MAX_VERTEX_NUM 20typdef enum{DG,DN,UDG,UDN}GraphKind;typedef struct{VertexType vexs[MAX_VERTEX_NUM];int arcs[MXA_VERTEX_NUM ] [MAX_VERTEX_NUM];int vexnum,arcnum;GraphKind kind;}MGraph;2_udg 邻接表
文章浏览阅读4.1w次,点赞10次,收藏56次。一步一步教你如何在AndroidStudio查看Android源码(AOSP源码)_如何用android studio 查看android源码
文章浏览阅读250次。<?php /** * curl多线程下载类 */class MultiHttpRequest{ public $urls = array (); private $res = array (); private $curlopt_header = 0; private $method = "GET"; private $curlopt = array (); ..._curl 多线程下载
文章浏览阅读1.9w次,点赞21次,收藏180次。51单片机AD转换电路设计实现关于AD转换的原理,大家在《数字电子技术》中已经学过,这里做过多的介绍,本文介绍一款经典的8位AD转换芯片ADC0804,基于51单片机设计AD转换电路,并完成测量值的转换。1 芯片引脚介绍CS:片选信号,低电平有效,即CS=0时候芯片才能正常工作,单独一个ADC0804芯片时候直接置零。当有多个芯片时候可以通过片选信号实现分时复用。WR:低电平有效,当WR信号由高到低时候实现一次ADC转换。RD:低电平有效,RD=0时候可以读取数据。Vin+:模拟电压输入端。_单片机ad转换原理
文章浏览阅读1.7k次,点赞3次,收藏14次。操作系统实验报告17实验内容实验内容:虚拟存储管理。编写一个 C 程序模拟实现课件 Lecture24 中的请求页面置换算法包括FIFO、LRU (stack and matrix implementation)、Second chance,并设计输入用例验证结果。实验环境架构:Intel x86_64 (虚拟机)操作系统:Ubuntu 20.04汇编器:gas (GNU Assembler) in AT&T mode编译器:gcc技术日志实验内容原理页_页式存储管理及页面置换算法操作系统实验报告
文章浏览阅读600次。人生是场长跑,你是同学中的哪一个?要知道,高中时候,大家的世界观人生观基本上已经形成了,但是高中时候成绩好的,过了20年来看,未必是事业上最成功的我这里举四个人的例子:A男,我最好的朋友,大学毕业就进入设计院,作为他们系最好的学生被某建筑设计院看中。他当年没考上研究生竟然也是他的运气,因为和他同届考上研究生的人毕业后成为他的下属的下属。37岁当上设计院院长,成为该设计院最年轻院长..._晚上好同学,明晚07:45你的第一节儿理财课就开始了,我是你接下来九天课的专
文章浏览阅读193次。编写一个本地Web项目,如下。使用Ctrl + F5以及点击三角运行均没有问题,但右键Run Code报错。_coderunner无法运行
文章浏览阅读56次。本文将简单介绍一下如下几种单元测试工具以及推荐一些学习资源。 1.NUnit 2.TestDriven.Net 3.NUnitForms 4.NUnitAsp 一.NUnit 提起大名鼎鼎的NUnit,我想没有几个不知道吧?NUnit是一个专门针对于.NET的单元测试框架。在这之前有针对Java的JUnit,针对 C++的 CPPUnit,它们都是属于xUni..._button tester
文章浏览阅读37次。4.强大的解码能力:DPO2002B示波器提供了多种解码选件,支持常见的串行协议和总线通信解码,如I2C、SPI、UART等,方便工程师对通信数据进行分析和验证。3.灵活的触发功能:示波器支持多种触发方式,如边沿触发、脉冲宽度触发和序列触发等,根据需要灵活设置触发条件,捕获感兴趣的波形。1.高性能参数:该示波器具备200 MHz的带宽和1 GS/s的实时采样率,可捕获和显示高频信号的细节,确保准确的测量结果。
文章浏览阅读832次,点赞21次,收藏18次。本系统带文档lw万字以上文末可领取本课题的JAVA源码参考。
文章浏览阅读876次,点赞17次,收藏20次。华为云AppCube:体验快速搭建微信问卷小程序_微信问卷小程序