【编程之美】2.5 寻找最大的k个数
有若干个互不相等的无序的数,怎么选出其中最大的k个数。
我自己的方案:因为学过找第k大数的O(N)算法,所以第一反应就是找第K大的数。然后把所有大于等于第k大的数取出来。
写这个知道算法的代码都花了2个多小时,反思,太慢了。 注意边界条件,不要混混沌沌的。
/************我自己的解法*****************/
//选择数组a[N]中最大的第k个数
int Select(int * a, int N, int k)
{
if(k > N || a == NULL)
{
cout << "error!!!";
}
if(N < )
{
qsort(a, N, sizeof(a[]), cmp);
return a[N - k];
}
int arrNum = N/; //可以整除5的数字
int surplus = N % ; //除以5剩下的数字
int * mid = new int [arrNum]; //存储每一组的中位数
int * S1 = new int [N];
int * S2 = new int [N];
int posS1 = ;
int posS2 = ; for(int i = ; i < arrNum; i++)
{
qsort(a+i*, , sizeof(a[]), cmp);
mid[i] = *(a + i * + );
} int midNum = Select(mid, arrNum, arrNum/); for(int i = ; i < arrNum; i++)
{
int * currentGroup = a + i * ;
if(currentGroup[] < midNum)
{
memcpy(S1 + posS1, currentGroup, * sizeof(a[]));
posS1 += ;
for(int j = ; j < ; j++)
{
if(currentGroup[j] <= midNum)
S1[posS1++] = currentGroup[j];
else
S2[posS2++] = currentGroup[j];
}
}
else
{
memcpy(S2 + posS2, currentGroup + , * sizeof(a[]));
posS2 += ;
for(int j = ; j < ; j++)
{
if(currentGroup[j] <= midNum)
S1[posS1++] = currentGroup[j];
else
S2[posS2++] = currentGroup[j];
}
} }
for(int i = arrNum * ; i < N; i++)
{
if(a[i] <= midNum)
S1[posS1++] = a[i];
else
S2[posS2++] = a[i];
} if(k == posS2)
{
return midNum;
}
else if(k < posS2)
{
return Select(S2, posS2, k);
}
else
{
return Select(S1, posS1, k - posS2);
} } int * GetBiggestK(int * a, int N, int k)
{
int * biggestK = new int [k];
int numK = Select(a, N, k);
int pos = ;
for(int i = ; i < N; i++)
{
if(a[i]>=numK)
{
biggestK[pos++] = a[i];
}
} return biggestK; }
编程之美对这种算法的评价是:由于这个线性算法的常数项比较大,在实际应用中有时效果并不好。
---------------------------------------------------------------------------------------------------------------------------
书上的解法:
解法一: 先排序,再取出最大的k个数 复杂度 O(NlogN)
解法二:类似于快速排序,先在数据中选一个数做标准,把数据划分为两个部分,大于等于选中数字S1个 和 小于选中数字S2个 。如果S1大于k则在S1个数中继续找最大的k个,如果S1小于k,则把这S1个数加入答案,并在S2中继续找其他的数字。 平均复杂度为O(NlogK).
/*********答案中 解法二*****************/
int * GetBiggestKAns2(int * a, int N, int k)
{
if(a == NULL || k > N)
{
cout << "error!!!"<< endl;
return NULL;
}
int first = a[];
int head = ;
int tail = N - ;
int numAlready = ; int postion = GetPosition(a, first, head, tail);
swap(a[], a[postion]); if(postion + == k)
{
int * ans = new int [k];
memcpy(ans, a, k * sizeof(a[]));
return ans;
}
else if(postion + > k)
{
return GetBiggestKAns2(a, postion + , k);
}
else
{
int * ans = new int [k];
memcpy(ans, a , (postion + ) * sizeof(a[]));
int * ansPart = GetBiggestKAns2(a + postion + , N - postion - , k - postion - );
memcpy(ans + postion + , ansPart, (k - postion - ) * sizeof(a[]));
return ans;
}
} //交换时让大数在前,小数在后
int GetPosition(int * a, int first, int p, int r)
{
int head = p;
int tail = r;
while(head < tail)
{
while(a[head] >= first)
head++;
while(a[tail] < first)
tail--;
if(head < tail)
{
swap(a[head], a[tail]);
head++;
tail--;
}
}
return head - ; //如果所有的数字都比first大 那么head会指向数组后的第一个数字
//如果所有的数字都比first小 那么head会指向第一个数字 都是恰好head - 1 是应该交换的位置
}
----------------------------------------------------------------------------------------------------
解法三:用二分法找第k大的数 数据分布平均情况下,时间复杂度为O(NlogN)
伪代码如下:
while(Vmax - Vmin > delta)
{
Vmid = Vmin + (Vmax - Vmin) * 0.5;
if(f(arr, N, Vmid) >= K)
{
Vmin = Vmid;
}
else
{
Vmax = Vmid;
}
}
f(arr, N, Vmid) 返回数组arr[0...N-1]中大于等于Vmid的数的个数。delta是比数组中数字的最小差值还要小的数。
最后[Vmid, Vmax]只剩下一个数,就是第k大的数。
另一个思路:若所有的数都是整数,可以比较他们的二进制位,从最高位开始,1的是较大的数 有A个,0的是较小的数有B个。若 A > K则在A中找最大的K个,反之 把A个数加入答案, 在B中找 最大的K - A个数。
----------------------------------------------------------------------------------------------------
解法四:用一个最小堆存储最大的那K个数,先把K个数加入最小堆,新来一个数就与最小堆的根节点对比,比根节点小丢弃,比根节点大则替换根节点,调整最小堆。这样遍历完后最小堆里的数字就是最大的K个数。 时间O(NlogK)
-----------------------------------------------------------------------------------------------------
解法五:若数字的范围是有限的整数,可以分配一个count[MAXN]的数组,count[0]记录0在数组中出现的次数...这样只要遍历一遍数组得到count再遍历一遍count就可以找到最大的K个数了。
【编程之美】2.5 寻找最大的k个数的更多相关文章
- 编程之美2.5:寻找最大的K个数
编程之美2.5:寻找最大的K个数 引申:寻找第k大的数: 方法一: // 选择第k大的数(通过改进快速排序来实现) public static void SelectShort(int[] array ...
- 算法系列:寻找最大的 K 个数
Copyright © 1900-2016, NORYES, All Rights Reserved. http://www.cnblogs.com/noryes/ 欢迎转载,请保留此版权声明. -- ...
- 算法练习:寻找最小的k个数
参考July的文章:http://blog.csdn.net/v_JULY_v/article/details/6370650 寻找最小的k个数题目描述:查找最小的k个元素题目:输入n个整数,输出其中 ...
- 第2章 数字之魅——寻找最大的K个数
寻找最大的K个数 问题描述 在面试中,有下面的问答: 问:有很多个无序的数,我们姑且假定它们各不相等,怎么选出其中最大的若干个数呢? 答:可以这样写:int array[100] …… 问:好,如果有 ...
- O(N)的时间寻找最大的K个数
(转:http://www.cnblogs.com/luxiaoxun/archive/2012/08/06/2624799.html) 寻找N个数中最大的K个数,本质上就是寻找最大的K个数中最小的那 ...
- 03寻找最小的k个数
题目描述:查找最小的k个元素 题目:输入n个整数,输出其中最小的k个. 例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4. 1:最简单 ...
- 寻找最大的k个数问题
这是编程之美书第2.5节的一道题目. 各种解法: 解法一,用nlgn复杂度的排序算法对数组进行从大到小排序,取前K个.但这方法做了两件不必要做的事:它对想得到的K个数进行了排序,对不想得到的n-K个数 ...
- 寻找最大的k个数
这个题目是非常经典的一个题目,解法也有很多,现在就把我已经理解的解法记录下来. 题目描述 有n个无序的数,它们各不相等,怎样选出其中的最大的k个数呢? 题目分析: 解法1: 最容易想到的就是把n个数进 ...
- 算法笔记_035:寻找最小的k个数(Java)
目录 1 问题描述 2 解决方案 2.1 全部排序法 2.2 部分排序法 2.3 用堆代替数组法 2.4线性选择算法 1 问题描述 有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低. 2 ...
随机推荐
- sql server cpu占用过高优化
SQLSERVER排查CPU占用高的情况 今天中午,有朋友叫我帮他看一下数据库,操作系统是Windows2008R2 ,数据库是SQL2008R2 64位 64G内存,16核CPU 硬件配置还是比较高 ...
- ggplot2 上篇
title: "ggplot2 上篇" author: "li_volleyball" date: "2016年4月16日" output: ...
- WebForm中搭配母版页和用户控件页时候的事件加载顺序
在生产环境中,一个内容页(aspx)可能会包含数个用户控件(ascx),而每个控件可能都会涉及到数据库访问. 如果在内容页.母版页.控件页中各自使用自己的数据库访问方法,会造成很大的运行成本. 这样的 ...
- [转]CentOS 5.3通过yum升级php到最新版本的方法
来自:www.jasonlitka.com/media 通过测试,方法三可行: 方法三 vim /etc/yum.repos.d/utterramblings.repo 输入 [utterrambli ...
- php访问全局变量
函数之外声明的变量拥有 Global 作用域,只能在函数以外进行访问. 函数内部声明的变量拥有 LOCAL 作用域,只能在函数内部进行访问. PHP 同时在名为 $GLOBALS[index] 的数组 ...
- mongodb 释放磁盘空间
db.copyDatabase("from","to","127.0.0.1:16161"); 将127.0.0.1上的from库.拷贝到t ...
- iOS开发——UI进阶篇(十五)Quartz2D介绍
一.Quartz2D简介 1.什么是Quartz2DQuartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能完成的工作绘制图形 : 线条\三角形\矩形\圆\弧等绘制文字绘 ...
- html5拖拽实现
1.需求 做一个h5正方形的拖拽框 2.分析 使用touchstart,touchmove,touchend这3个事件实现. 需要记录的数据有三组数据,分别是下图的(x0,y0),(x1,y1),(x ...
- Tomcat无法启动问题
检查环境变量设置 再打开一个cmd, 1.输入if not exist "%JRE_HOME%\bin\java.exe" echo no jre java 回车 结果:no ...
- HDU 2855 斐波那契+矩阵快速幂
http://acm.hdu.edu.cn/showproblem.php?pid=2855 化简这个公式,多写出几组就会发现规律 d[n]=F[2*n] 后面的任务就是矩阵快速幂拍一个斐波那契模板出 ...