查找之找出N个整数中最大的K个数

题目一:找出N个整数中第K大的数

类似下边的类快排算法,递归实现,应该可以,需要验证一下。平均复杂度O(n).



题目二:找出N个整数中最大的K个数

两个比较好的解法:O(nlogk)

1快排和递归

【解法二】

回忆一下快速排序,快排中的每一步,都是将待排数据分做两组,其中一组
的数据的任何一个数都比另一组中的任何一个大,然后再对两组分别做类似的操
作,然后继续下去……

在本问题中,假设 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 *
log2K)。伪代码如下:

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])
// 将p加入较小的组, 可以避免分组失败, 也使分组更均匀,提高效率
length Sa < length Sb ? Sa.Append(p) : Sb.Append(p)
return (Sa, Sb)

2 堆排序

不妨设 N > K,前 K 个数中的最大 K 个数是一个退化的情况,所有 K 个数
就是最大的 K 个数。如果考虑第 K+1 个数 X 呢?如果 X 比最大的 K 个数中的最
小的数 Y 小,那么最大的 K 个数还是保持不变。如果 X 比 Y 大,那么最大的 K
个数应该去掉 Y,而包含 X。如果用一个数组来存储最大的 K 个数,每新加入一
个数 X,就扫描一遍数组,得到数组中最小的数 Y。用 X 替代 Y,或者保持原数
组不变。这样的方法,所耗费的时间为 O(N * K)。

进一步,可以用容量为 K 的最小堆来存储最大的 K 个数。最小堆的堆顶元
素就是最大 K 个数中最小的一个。每次新考虑一个数 X,如果 X 比堆顶的元素
Y 小,则不需要改变原来的堆,因为这个元素比最大的 K 个数小。如果 X 比堆
顶元素大,那么用 X 替换堆顶的元素 Y。在 X 替换堆顶元素 Y 之后,X 可能破
坏最小堆的结构(每个结点都比它的父亲结点大),需要更新堆来维持堆的性
质。更新过程花费的时间复杂度为 O(log2K)。



 编程之美

图 2-1 是一个堆,用一个数组 h[]表示。每个元素 h[i],它的父亲结点是 h[i/2],
儿子结点是 h[2 * i + 1]和 h[2 * i + 2]。每新考虑一个数 X,需要进行的更新操作伪
代码如下:

if(X > h[0])
{
h[0] = X;
p = 0;
while(p < K)
{
q = 2 * p + 1;
if(q >= K)
break;
if((q < K-1) && (h[q + 1] < h[q]))
q = q + 1;
if(h[q] < h[p])
{
t = h[p];
h[p] = h[q];
h[q] = t;
p = q;
}
else
break;
}
}

原帖:http://blog.csdn.net/scottgly/article/details/6958227
原文地址:https://www.cnblogs.com/catkins/p/5270739.html