【发布时间】:2010-11-05 07:28:42
【问题描述】:
嘿。我有一个非常大的数组,我想找到第 N 个最大值。很简单,我可以对数组进行排序,然后取第 N 个元素,但我只对一个元素感兴趣,所以可能有比对整个数组进行排序更好的方法......
【问题讨论】:
嘿。我有一个非常大的数组,我想找到第 N 个最大值。很简单,我可以对数组进行排序,然后取第 N 个元素,但我只对一个元素感兴趣,所以可能有比对整个数组进行排序更好的方法......
【问题讨论】:
堆是此操作的最佳数据结构,Python 有一个出色的内置库来执行此操作,称为 heapq。
import heapq
def nth_largest(n, iter):
return heapq.nlargest(n, iter)[-1]
示例用法:
>>> import random
>>> iter = [random.randint(0,1000) for i in range(100)]
>>> n = 10
>>> nth_largest(n, iter)
920
通过排序确认结果:
>>> list(sorted(iter))[-10]
920
【讨论】:
排序至少需要 O(nlogn) 运行时间 - 有非常高效的 selection algorithms 可以在线性时间内解决您的问题。
Partition-based selection(有时是Quick select),它基于快速排序(递归分区)的思想,是一个很好的解决方案(参见伪代码链接+Another example)。
【讨论】:
一个简单的修改过的快速排序在实践中效果很好。它的平均运行时间与 N 成正比(尽管最坏情况下的运行时间是 O(N^2))。
像快速排序一样进行。随机选择一个枢轴值,然后通过您的值流式传输并查看它们是否高于或低于该枢轴值,并根据该比较将它们放入两个箱中。 在快速排序中,您将递归地对这两个箱中的每一个进行排序。但是对于第 N 个最高值的计算,您只需要对一个 bin 进行排序。每个 bin 的数量会告诉您哪个 bin 拥有您的第 n 个最高值。因此,例如,如果您想要第 125 个最高值,并且您将其分类为两个箱,其中 75 在“高”箱中,150 在“低”箱中,您可以忽略高箱并继续查找 125-75 =仅在低箱中的第 50 个最高值。
【讨论】:
您可以迭代整个序列,维护您找到的 5 个最大值的列表(这将是 O(n))。话虽如此,我认为对列表进行排序会更简单。
【讨论】:
您可以尝试 Median of Medians 方法 - 它的速度是 O(N)。
【讨论】:
使用堆排序。它只是对列表进行部分排序,直到您将元素绘制出来。
【讨论】:
您实际上想要生成一个“top-N”列表并选择该列表末尾的那个。
因此,您可以扫描一次数组并在 largeArray 项目大于前 N 列表的最后一项时插入一个空列表,然后删除最后一项。
完成扫描后,选择前 N 个列表中的最后一项。
整数和 N = 5 的示例:
int[] top5 = new int[5]();
top5[0] = top5[1] = top5[2] = top5[3] = top5[4] = 0x80000000; // or your min value
for(int i = 0; i < largeArray.length; i++) {
if(largeArray[i] > top5[4]) {
// insert into top5:
top5[4] = largeArray[i];
// resort:
quickSort(top5);
}
}
【讨论】:
正如人们所说,只要跟踪 K 个最大值,您就可以遍历列表。如果 K 很大,这个算法将接近 O(n2)。
但是,您可以将第 K 个最大值存储为二叉树,操作变为 O(n log k)。
根据维基百科,这是最好的选择算法:
function findFirstK(list, left, right, k)
if right > left
select pivotIndex between left and right
pivotNewIndex := partition(list, left, right, pivotIndex)
if pivotNewIndex > k // new condition
findFirstK(list, left, pivotNewIndex-1, k)
if pivotNewIndex < k
findFirstK(list, pivotNewIndex+1, right, k)
它的复杂度是O(n)
【讨论】:
如果这是在生产代码中,您应该做的一件事是使用数据样本进行测试。 例如,您可能会考虑 1000 或 10000 个元素的“大”数组,并从配方中编写快速选择方法。
sorted 的编译特性,以及它有些隐藏和不断发展的优化,使其在中小型数据集(
因此,即使 quickselect 是 O(n) 与 sorted 的 O(nlogn),这也没有考虑处理每个 n 元素需要多少实际机器代码指令,对流水线的任何影响,处理器缓存的使用和sorted 的创建者和维护者会在 python 代码中添加其他内容。
【讨论】:
您可以为每个元素保留两个不同的计数 - 大于该元素的元素数和小于该元素的元素数。
然后做一个 if 检查 N == 比每个元素大的元素数 -- 满足上述条件的元素就是你的输出
检查以下解决方案
def NthHighest(l,n):
if len(l) <n:
return 0
for i in range(len(l)):
low_count = 0
up_count = 0
for j in range(len(l)):
if l[j] > l[i]:
up_count = up_count + 1
else:
low_count = low_count + 1
# print(l[i],low_count, up_count)
if up_count == n-1:
#print(l[i])
return l[i]
# # find the 4th largest number
l = [1,3,4,9,5,15,5,13,19,27,22]
print(NthHighest(l,4))
-- 使用上述解决方案,您可以找到两者 - Nth highest as well as Nth Lowest
【讨论】:
如果你不介意使用 pandas,那么:
import pandas as pd
N = 10
column_name = 0
pd.DataFrame(your_array).nlargest(N, column_name)
上面的代码将显示N个最大值以及每个值的索引位置。
希望对您有所帮助。 :-)
【讨论】: