11073 最热门的K个搜索串
时间限制:350MS 内存限制:65535K
提交次数:0 通过次数:0

题型: 编程题 语言: G++;GCC;VC
Description
大家都非常喜欢而习惯用baidu,google,sogou等搜索引擎来搜索自己感兴趣的资料。
搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。
假设目前有一百万个记录(这些查询串的重复度比较高,除去重复后会少很多)。
搜索引擎统计查询串的重复频度,一个查询串的重复频度越高,说明查询它的用户越多,也就是越热门。
希望能找到最热门的10个或100个查询串。

现在问题模型是:一个无序的整数数列,数列元素个数为N,1000<=N<=1000000,
如何选出其中最大的K个数,K远小于N(K<<N, K<1000),
比如Top10的数,或Top100的数等。本意并不要求选出的这K个数有序,也不要求剩余的N-K个数有序。
但最终输出为便于评判,还是要求排序的,具体看如下说明(3)。

说明:
(1)虽然此题N较大,还是可以一次性将整数数列导入内存的。

(2)此题认为N较大,不适合对所有元素排序后取得“最大的K个数”,
此排序法复杂度O(NlogN),请你勿用此法,否则将判超时。请选用低于O(NlogN)阶的算法来做。

(3)此题原本是不要求选出的K个数有序,但为了在本OJ(Oline Judge)系统上便于评判,
还是请您以从大至小的不增顺序输出。

输入格式
输入:两行,第一行N和K,第二行为N个无序整数

输出格式
输出:这N个无序整数的最大的K个数

输入样例
20 6
9 1 2 5 3 2 3 4 10 7 1 5 7 6 4 8 9 6 7 5

输出样例
10 9 9 8 7 7

提示

这个问题就是在海量的N个数中求最大的K个数,K<<N。
上课时非常仔细讲解过这个问题,可以用多种方法来求解。
比较好的就是用(1)堆的方法,或(2)快速选择算法。

对算法(1):

1. 先建一个长度为K的最小堆,存储N个元素的前K个元素,并假设他们就是最大的K个数,建堆费时O(K);
2. 弹堆顶x,将后续N-K个元素逐个遍历,和堆顶x比较,若比x大,插入并更新堆,若比x小,丢弃;
3. 后续N-K个遍历完后,这个最小堆中的所有元素就是前K大了。将堆顶逐个输出就达到题目的有序输出的要求了。
总耗时最坏:O(K+(N-K)logK) = O(NlogK),当K较小,接近线性效率,且堆的空间很小(只有K),非常适合于海量数据查询第K大元素(K<<N)。
此方法得益于在堆中,插入、查找等各项操作时间复杂度均为logK。即使是求第K小,前K小,第K大,前K大也都是同理的。

对算法(2):

采用快速选择算法,选支点元素时,用随机选择一个支点元素为宜(书上P27的算法),一般情况运行性能都很好。
倒是无须用“中位数的中位数”(P28的算法)做支点元素来完成,当然你想试试也不赖。
第K大元素找到后,做过Partition之后,第K大元素之后段(含第K大)的就是比第K大还大的前K大了。再对前K大排序输出即可。

用第K大做:

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = + ;
int myRand(int be, int en) {
return be + (rand() % (en - be + ));
}
int findKthMin(int a[], int be, int en, int k) {
if (be == en) return be;
swap(a[be], a[myRand(be, en)]);
int one = be, two = en, id = be;
while (one != two) {
while (two > one && a[two] >= a[id]) --two; // 找第一个比id小的, 必须先找小的
while (one < two && a[one] <= a[id]) ++one; // 找第一个比id大的, 因为基准数是be
if (one < two) swap(a[one], a[two]);
//需要从右到左是因为,如果是从左到右,例子1、2、3、4、5
//找到第一个比1大的,是2,然后找不到第一个比1小,在2中相遇
//然后swap(a[1], a[2]) GG }
swap(a[id], a[one]);
int hasKey = one - be + ; // 有多少个元素
if (hasKey >= k) return findKthMin(a, be, one, k);
else return findKthMin(a, one + , en, k - hasKey);
}
int a[maxn];
void work() {
int n, k;
scanf("%d%d", &n, &k);
for (int i = ; i <= n; ++i) {
scanf("%d", a + i);
}
int id = findKthMin(a, , n, n - k + );
sort(a + id, a + + n);
for (int i = n; i >= id; --i) {
printf("%d ", a[i]);
}
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
work();
return ;
}

用堆做,类似于K打擂算法,首先选K个擂主,然后每次打死一个最小的,那么剩下的优先队列里面的K个元素就是最大的K个了。

复杂度O(Nlogk)空间只需O(k)

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
const int maxn = + ;
int a[maxn];
priority_queue<int, vector<int>, greater<int> > que;
void work() {
int n, k;
scanf("%d%d", &n, &k);
for (int i = ; i <= n; ++i) {
scanf("%d", a + i);
}
for (int i = ; i <= k; ++i) {
que.push(a[i]);
}
for (int i = k + ; i <= n; ++i) {
int now = que.top();
if (a[i] > now) {
que.pop();
que.push(a[i]);
}
}
for (int i = ; i <= k; ++i) {
a[i] = que.top();
que.pop();
}
for (int i = k; i >= ; --i) {
printf("%d ", a[i]);
}
} int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
work();
return ;
}

11073 最热门的K个搜索串的更多相关文章

  1. 后缀自动机求字典序第k小的串——p3975

    又领悟到了一点新的东西,后缀自动机其实可以分为两个数据结构,一个是后缀树,还有一个是自动机 后缀树用来划分endpos集合,并且维护后缀之间的关系,此时每个结点代表的是一些后缀相同且长度连续的子串 自 ...

  2. hdu-6194 string string string 后缀数组 出现恰好K次的串的数量

    最少出现K次我们可以用Height数组的lcp来得出,而恰好出现K次,我们只要除去最少出现K+1次的lcp即可. #include <cstdio> #include <cstrin ...

  3. 2015年上海现场赛重现 (A几何, K暴力搜索)

    A: 题目链接 :https://vjudge.net/contest/250823#problem/A 参考 : https://www.cnblogs.com/helenawang/p/54654 ...

  4. 10.N个整数中查找是否相加为K[深度搜索]

    /*摘自书本,这种算法很绕!*/ #include <iostream> using namespace std; ,,,}; ; bool dfs(int i,int sum) { if ...

  5. Codeforces Gym100971 K.Palindromization-回文串 (IX Samara Regional Intercollegiate Programming Contest Russia, Samara, March 13)

    这个题就是从字符串中删除一个字符,然后剩下的是回文串. 我写的代码虽然长得好看,但是循环里面的比较条件容易想错,太智障了... 一开始写的是计数比较,但是有的时候下标相同的也比较了,为了简单一些,直接 ...

  6. Trie树(字典树) 最热门的前N个搜索关键词

    方法介绍 1.1.什么是Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优 ...

  7. 程序员编程艺术第三十六~三十七章、搜索智能提示suggestion,附近点搜索

    第三十六~三十七章.搜索智能提示suggestion,附近地点搜索 作者:July.致谢:caopengcs.胡果果.时间:二零一三年九月七日. 题记 写博的近三年,整理了太多太多的笔试面试题,如微软 ...

  8. 程序员编程艺术:第三章续、Top K算法问题的实现

    程序员编程艺术:第三章续.Top K算法问题的实现 作者:July,zhouzhenren,yansha.     致谢:微软100题实现组,狂想曲创作组.     时间:2011年05月08日    ...

  9. 海量数据处理 - 10亿个数中找出最大的10000个数(top K问题)

    前两天面试3面学长问我的这个问题(想说TEG的3个面试学长都是好和蔼,希望能完成最后一面,各方面原因造成我无比想去鹅场的心已经按捺不住了),这个问题还是建立最小堆比较好一些. 先拿10000个数建堆, ...

随机推荐

  1. jquery ajax 分页2

    /* * 分页 $("#divPager").flexipager * 2015.03.17 */ //初始化列表默认属性 (function($) { $.addFlex = f ...

  2. MVC中使用代码创建数据库(code first +mysql+EF)

    1.新建一个mvc项目 2.安装mysql需要的几个文件 EntityFramework.MySql.Data(6.9.12)和MySql.Data.Entity (6.9.12) 这里有几点要注意 ...

  3. 关于UI Automation框架

    微软提供的UI Automation框架给开发windows平台的自动化测试带来了很大的便利,这里就总结一下相关的代码. 首先,直接使用UI Automation框架,完成一个NotePad的abou ...

  4. JavaAppArguments示例

    本实验要求编写一个程序,此程序从命令行接收多个数字,求和之后输出结果.一大难点是命令行参数都是字符串,必须先将其转化为数字,才能相加. 中心想法就是将求和数字转换为整型并依次相加. 程序流程图: pu ...

  5. Java从入门到放弃——05.修饰符static,final,权限修饰符

    本文目标 static final: 权限修饰符:public,private,protected,缺省 1.static 静态修饰符,被static修饰的变量或者方法会被加载进静态区内存,不需要创建 ...

  6. iOS中Info.plist文件的常见配置

    . 在创建一个新的Xcode工程后,会 在Supporting Files文件夹下自动生成一个工程名-Info.plist的文件,这个是对工程做一些运行期配置的文件(很重要,必须有该文件). 如果使用 ...

  7. mybatis、Spring整合(eclipse)以及事务管理

    1.项目目录 2.jar包 dbcp:连接池 pool:连接池 logging:日志 log4j:日志 mybatis-spring:用于SqlSession等相关操作 spring相关包 mybat ...

  8. C#中工厂模式的作用

    1.比如,主要用于对扩展性有要求的功能. 以简单工厂为例: 接口Fun有三个实现 class FunA FunB FunC工厂 class Fac {   public static Fun getF ...

  9. loj #2037. 「SHOI2015」脑洞治疗仪

    #2037. 「SHOI2015」脑洞治疗仪   题目描述 曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪——一种可以治疗他因为发明而日益增大的脑洞的神秘装置. 为了简单起见 ...

  10. 解决三星官方移植的内核默认是没有打开支持V4L USB devices

         在linux比较新的kernel,都标配了各类摄像头的驱动支持,不用我们自己移植驱动,只需通过make menuconfig配置内核支持我们所需的摄像头类型即可.以下是在三星官方内核中配置V ...