原贴:http://bbs.hadoopor.com/thread-138-1-1.html
现有1亿个整数均匀分布,如果要得到前1K个最大的数,求最优的算法。
(先不考虑内存的限制,也不考虑读写外存,时间复杂度最少的算法即为最优算法)
我先说下我的想法:分块,比如分1W块,每块1W个,然后分别找出每块最大值,从这最大的1W个值中找最大1K个,那么其他的9K个最大值所在的块即可扔掉,从剩下的最大的1K个值所在的块中找前1K个即可。那么原问题的规模就缩小到了1/10。
问题:
1.这种分块方法的最优时间复杂度。
2.如何分块达到最优。比如也可分10W块,每块1000个数。则问题规模可降到原来1/100。但事实上复杂度并没降低。
3.还有没更好更优的方法解决这个问题。
希望大家来讨论讨论,踊跃提出自己的解决方式和思路。
现有1亿个整数均匀分布,如果要得到前1K个最大的数,求最优的算法。
(先不考虑内存的限制,也不考虑读写外存,时间复杂度最少的算法即为最优算法)
我先说下我的想法:分块,比如分1W块,每块1W个,然后分别找出每块最大值,从这最大的1W个值中找最大1K个,那么其他的9K个最大值所在的块即可扔掉,从剩下的最大的1K个值所在的块中找前1K个即可。那么原问题的规模就缩小到了1/10。
问题:
1.这种分块方法的最优时间复杂度。
2.如何分块达到最优。比如也可分10W块,每块1000个数。则问题规模可降到原来1/100。但事实上复杂度并没降低。
3.还有没更好更优的方法解决这个问题。
希望大家来讨论讨论,踊跃提出自己的解决方式和思路。
解决方案 »
- 使用HttpClient提交淘宝表单问题
- 关于FileIO的基础问题,请指教。
- 为什么improt 不能导入程序库呢!
- 现在有字符串,如下:5,3,8,2,9,4 请按照升序和降序打印,情问怎么把这个字符串转换成一个int 型的数组啊?
- 用split分字符串,遇到“?”号为什么不行呢?
- Oracle 10g的连接串怎么写?
- 加急请教一简单问题!晕了
- 上海哪里有专业的计算机书店,最新最全的~~~
- 在forte for java 4的Source Editor中编辑jsp时候,可以输入中文,可是保存后关闭再打开,中文显示???,怎么回事啊
- 请问各位前辈,我把java作为我的第一门计算机语言如何?
- 通过java代码如何把改变xml文件的字符编码格式
- 在java AWT 中怎么隐藏TextArea的光标?
List<Integer> lst = new ArrayList<Integer>();
int numberCount = 1000000000;
int maxNumber = numberCount;
Random random = new Random();
for (int i = 0; i < numberCount; i++) {
int randomInt = random.nextInt(maxNumber);
Integer inte = new Integer(randomInt);
if (set.contains(inte))
{
lst.add(inte);
}
if (set.size() < 1000)
{
set.add(inte);
}
else
{
if (set.first().intValue() < randomInt)
{
set.remove(set.first());
set.add(randomInt);
}
}
}Iterator iterator = set.iterator();
while(iterator.hasNext()) {
lst.add((Integer)iterator.next());
}Collections.sort(lst);
for (int i = 0; i < 1000; i++)
{
System.out.println(i + ":" + lst.get(lst.size() - i - 1));
}套个main就可以跑了,耗时大概在100S左右,每1KW用时不到2S。
假设N个数存储在数组S中,我们从数组S中随机选出一个元素X,把数组分为两部分Sa和Sb.Sa中的元素都大于X,Sb中的元素都小于X:
这是,有两种可能性:
1.Sa中元素的个数小于K,Sa中所有的数和Sb中最大的K-|Sa|个数(|Sa|指Sa中元素的个数)就是数组S中最大的K个数。
2.Sa中元素的个数大于或等于K,则直接返回Sa中最大的K个元素。
平均时间复杂度O(N*log2 K)
伪代码:Kbig(S,K)
if(k<=0):
return []
if(length S<=K):
return S
(Sa,Sb)=Partition(s)
return Kbig(Sa,k).Append(Kbig(Sb,k-length Sa)
//////////////////////////////////////////////////
Partition(S):
Sa=[];
Sb=[];
Swap(s[1],S[random()%length S])
p=S[1]
for i in [2:length S]:
s[i] > p ? Sa.Append(s[i]):Sb.Append(S[i])length Sa<length Sb ? Sa.Append(p):Sb.Append(p)
return (Sa,Sb)
我的代码:#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <time.h>
using namespace std;
vector<int> Kbig(vector<int>&,int);
pair<vector<int>,vector<int> > Partition(vector<int>);
int main()
{
vector<int> origin(10000,0);
int k;
cout <<"origin array:"<<endl;
for (int i = 0;i < 10000;i++)
{
origin[i] = rand() % 10001;
cout << origin[i] << " ";
}
cout << endl;
cout << "请输入你想找的最大的数的个数:"<<endl;
cin >> k;
origin = Kbig(origin,k);
cout << "最大的" << k << "个数是:"<< endl;
for(vector<int>::iterator iter = origin.begin();iter != origin.end(); ++iter )
cout << *iter <<" ";
cout << endl;
return 0;
}
vector<int> Kbig(vector<int>& origin,int k)
{
pair<vector<int>,vector<int> > ret;
vector<int> sa,sb,temp;
if(k <= 0)
return origin;
if(origin.size() <= k)
return origin;
ret = Partition(origin);
sa = ret.first;
sb = ret.second;
if (sa.size() >= k)
{
return Kbig(sa,k);
}
else
{
temp = Kbig(sb,k - sa.size());
for (vector<int>::iterator iter = temp.begin(); iter != temp.end();++ iter)
{
sa.push_back(*iter);
}
return sa;
}
}
pair<vector<int>,vector<int> > Partition(vector<int> origin)
{
srand((unsigned)time(NULL));
vector<int> sa,sb;
pair<vector<int>,vector<int> > ret;
int p;
swap(origin[0],origin[rand()%origin.size()]);
p = origin[0];
for (vector<int>::iterator iter = origin.begin() + 1;iter != origin.end();++iter)
*iter > p ? sa.push_back(*iter) : sb.push_back(*iter);
sa.size() < sb.size() ? sa.push_back(p) : sb.push_back(p);
ret = make_pair(sa,sb);
return ret;
}
位图算法。
楼主不妨可以看一看。题目给的条件是一亿个(10000*10000)整数均匀分布,那么这1Y个整数按照题目所述,应该有重复、漏掉(即不可能是从1~1Y)。
那么我现在给的一个算法是:1、定义二维数组 int Numbers[10000][10000]
2、初始化 Numbers[i][j]=0 (0<=i,j<10000)
3、遍历所给的1Y个数据,数据 CurrentNumber则应该放置在 Numbers[CurrentNumber/1000][CurrentNumber%1000],即Numbers[CurrentNumber/1000][CurrentNumber%1000]++Tips:
(1)上面Numbers[CurrentNumber/1000][CurrentNumber%1000]++是针对不可漏掉重复数据,比如9999999 有五个,那么它如果在前1K内,应该会占五个名额...4、最后一步开始从Numbers[9999][9999]开始输出前1K个数据
当Numbers[i][j]==0时不计算在内
党Numbers[i][j]!=0时,按照Numbers个数输出 i*10000+j (i*10000+j这个才是真正的数)
知道总计1K个数据输出完毕。我测试过,用C语言实现这样的算法,遍历完1Y个数据并输出前1K个,耗时不会太长,可以在几秒内。
如果用hadoop和mapreduce分块的话,其分块的过程就要耗费好多资源的。
over如果上述内容能给你一点点启发,不胜荣幸。