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. DNS线路

    文章介绍 填写DNS地址时候,比较好记的就114.114.114.114,8.8.8.8,9.9.9.9,几个,但是常用的有哪些呢?这篇文章就简单介绍下了. 前言 两年多前,曾发帖对国内主流公共 DN ...

  2. android中SharedPreferences 读取不到数据的问题

    在两个不同的 Activity中,A中SharedPreferences保存了数据,在A中可以读取到,但是在 B中却读取不到了,一直是空值,好是不爽,由于是按照书本上的例子写的, 怎么也找不到原因,后 ...

  3. Cookies的两种存取方式

    我们在使用webview开发时,少不了和cookie打交道,在网页端我这使用的是asp.net开发的,安卓下的cookie和windows平台下还是有些不同的,后来看了看,原来有两种cookie的存取 ...

  4. js 代码收集

    //获取image src路径 $(".userImg").click(function(){ var imgsrc = $(this).attr("src") ...

  5. 使用metasploit进行栈溢出攻击-3

    有了shellcode,就可以进行攻击了,但是要有漏洞才行,真实世界中的漏洞很复杂,并且很难发现,因此我专门做一个漏洞来进行攻击. 具体来说就是做一个简单的tcp server,里面包含明显的栈溢出漏 ...

  6. 扒一扒spring,dom4j实现模拟实现读取xml

    今天leadr提出需求,原来公司项目中读取解析xml文件的代码效率太低,考虑切换一种xml为数据封装格式与读取方式以提高效率.我这灵机一动spring对bean的依赖注入就是读取xml文件,可以尝试扒 ...

  7. tomcat - 认识

    tomcat - web应用服务器 环境:ubuntu测试 @shell命令(cd到tomcat目录下) 启动: ./bin  startup.sh 关闭:./bin  shutdown.sh @部署 ...

  8. Task4

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. Linux下oracle开机自启动服务

    如果每次重启操作系统都要进行以上操作好麻烦,那么如何让Oracle作为系统服务在开机的时候自动启动呢? Oracle在$ORACLE_HOME/bin下提供许多对数据库进行操作的脚本,其中dbstar ...

  10. 这些年、我收集的JQuery代码 (转)

    1. 如何创建嵌套的过滤器 //允许你减少集合中的匹配元素的过滤器, //只剩下那些与给定的选择器匹配的部分.在这种情况下, //查询删除了任何没(:not)有(:has) //包含class为“se ...