每天一道算法题(14)——N个降序数组,找到最大的K个数
题目:
假定有20个有序数组,每个数组有500个数字,降序排列,数字类型32位uint数值,现在需要取出这10000个数字中最大的500个。
思路
(1).建立大顶堆,维度为数组的个数,这里为20(第一次
插入的是每个数组中最大的值,即第一个元素)。
(2).删除最大堆堆顶,保存到数组或者栈中,然后向最大堆插入删除的元素所在数组的下一个元素。
(3).重复第1,2个步骤,直到删除个数为最大的K个数,这里为500.
代码
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std; #define ROWS 20
#define COLS 500 int data[ROWS][COLS]; void CreateData()
{
for(int i=0; i<ROWS; i++)
for(int j=0; j<COLS;j++)
data[i][j] = rand(); //生成随机元素
for( int i=0; i<ROWS; i++)
sort(data[i],data[i]+COLS, greater<int>()); //对每一行降序排列
}
//十分重要
struct Node
{
int *p; //指向某个列,因为要放入优先队列中,所以要比较大小,就用结构体封装了下
bool operator<(const Node &node) const
{
return *p < *node.p;
}
}; void OutMinData( int k)
{
struct Node arr[ROWS];
for(int i=0; i<ROWS;i++)
arr[i].p = data[i]; //初始化指针指向各行的第1列的地址
priority_queue<Node > queue( arr, arr+ROWS ); //使用优先队列,默认是大堆,此时需要调用node定义中的“<”重载函数 for( int i=0; i<k&&i<COLS; i++) //算法核心就是这个循环
{
Node temp = queue.top(); //取出队列中最大的元素
cout << *temp.p << " " <<endl;
queue.pop(); //从队列里删除
temp.p++; //对应行指针后移
queue.push( temp ); //这里面有log(ROWS)次操作,所以算法的总复杂度为O(klog(20))
} } int main()
{
CreateData(); //生成数据
int k=500;
OutMinData( k ); //输出k个元素,这里k不要大于列数COL,可以改进,去掉这个限制,不过会让程序不好懂,就没加
return 0;
}
分析
(1),压入大顶堆的元素为Node类型。因此创建大根堆时,需要重载“<”函数
(2).每次弹出最大值,压入新的值时。最多需要调整log(20)次,因此总共时间复杂度为O(500*log(20))
(3).sort()默认升序排列,因此需要加入仿函数greater<int>
(4)data[i]+j==&data[i][j]==*(data+i)+j,&data[i]==data+i
扩展
倘若非已经排序好的元素的同样数组求最大的前k个数。可以建立高度为log(k)的小根堆。遍历所有数组,每次删除根节点即最小的值,加入节点调整堆。时间复杂度为O(10000*log(500))
参考:
每天一道算法题(14)——N个降序数组,找到最大的K个数的更多相关文章
- 《github一天一道算法题》:分治法求数组最大连续子序列和
看书.思考.写代码. /*************************************** * copyright@hustyangju * blog: http://blog.csdn. ...
- 【算法题 14 LeetCode 147 链表的插入排序】
算法题 14 LeetCode 147 链表的插入排序: 解题代码: # Definition for singly-linked list. # class ListNode(object): # ...
- 算法题14 小Q歌单,牛客网,腾讯笔试题
算法题14 小Q歌单,牛客网,腾讯笔试题 题目: 小Q有X首长度为A的不同的歌和Y首长度为B的不同的歌,现在小Q想用这些歌组成一个总长度正好为K的歌单,每首歌最多只能在歌单中出现一次,在不考虑歌单内歌 ...
- 每天一道算法题(4)——O(1)时间内删除链表节点
1.思路 假设链表......---A--B--C--D....,要删除B.一般的做法是遍历链表并记录前驱节点,修改指针,时间为O(n).删除节点的实质为更改后驱指针指向.这里,复制C的内容至B(此时 ...
- [算法]找到无序数组中最小的K个数
题目: 给定一个无序的整型数组arr,找到其中最小的k个数. 方法一: 将数组排序,排序后的数组的前k个数就是最小的k个数. 时间复杂度:O(nlogn) 方法二: 时间复杂度:O(nlogk) 维护 ...
- 从一道算法题实现一个文本diff小工具
众所周知,很多社区都是有内容审核机制的,除了第一次发布,后续的修改也需要审核,最粗暴的方式当然是从头再看一遍,但是编辑肯定想弄死你,显然这样效率比较低,比如就改了一个错别字,再看几遍可能也看不出来,所 ...
- 【每天一道算法题】时间复杂度为O(n)的排序
有1,2,……一直到n的无序数组,求排序算法,并且要求时间复杂度为O(n),空间复杂度为O(1),使用交换,而且一次只能交换两个数. 这个是以前看到的算法题,题目不难.但是要求比较多,排序算法中,时间 ...
- 每天一道算法题-leetcode136-只出现一次的数字
前言 打卡第一天 2019.10.26日打卡 算法,即解决问题的方法.同一个问题,使用不同的算法,虽然得到的结果相同,但是耗费的时间和资源是不同的.这就需要我们学习算法,找出哪个算法更好. 大家都知道 ...
- 提前批笔试一道算法题的Java实现
题目描述 这是2021广联达校招提前批笔试算法题之一. 我们希望一个序列中的元素是各不相同的,但是理想和显示往往是有差距的.现在给出一个序列A,其中难免有相同的元素,现在提供了一种变化方式,使得经过若 ...
随机推荐
- 如何破解mssql for linux 3.5G内存的限制
在上有篇博客中主要介绍了如何在CentOS 中安装和配置mssql ,在安装过程中遇到3.5G内存的限制,下面介绍如何去破解, 微软发布了SQLServer for Linux,但是安装竟然需要3.5 ...
- android:descendantFocusability用法简析(转)
开发中很常见的一个问题,项目中的listview不仅仅是简单的文字,常常需要自己定义listview,自己的Adapter去继承BaseAdapter,在adapter中按照需求进行编写,问题 ...
- vue项目组件的全局注册
在vue-cli项目中,我们经常会封装自己的组件,并且要在多个界面中引用它,这个时候就需要全局注册组件. 首先我们会封装自己的组件,比如twoDimensionTable文件夹下的index.vue: ...
- 关于stl advance函数移动步数超过容器大小(越界)的研究
今天使用advance遇到个问题,当advance移动步数超过容器大小时,表现的结果居然不一样. 再来看下stl源码 template<typename _BidirectionalIterat ...
- [转]C++ 智能指针详解
转自:http://blog.csdn.net/xt_xiaotian/article/details/5714477 C++ 智能指针详解 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每 ...
- BZOJ - 4196 软件包管理器 (树链剖分+dfs序+线段树)
题目链接 设白色结点为未安装的软件,黑色结点为已安装的软件,则: 安装软件i:输出结点i到根的路径上的白色结点的数量,并把结点i到根的路径染成黑色.复杂度$O(nlog^2n)$ 卸载软件i:输出结点 ...
- HDU - 2294: Pendant(矩阵优化DP&前缀和)
On Saint Valentine's Day, Alex imagined to present a special pendant to his girl friend made by K ki ...
- mapreduce-实现多表关联
//map package hadoop3; import java.io.IOException; import org.apache.hadoop.io.LongWritable;import o ...
- bzoj 1798 [Ahoi2009]Seq 维护序列seq ——线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1798 先乘后加,就可给加法标记乘上乘法标记. 注意可能有 *0 的操作,所以 pshd 时不 ...
- dwd面试记录与最近面试的一些感想。
因为自己简历有些问题,额,面试官以为我有三年的工作经验. (吐槽一些智联的简历系统,)16年工作,一到18年自动变三年.这也忒坑人了. 工作年限一定要真实,避免出现问题,这会让面试官觉得你很不真诚. ...