我想知道我的思路是否正确。
我正准备接受采访(作为一名大学生),我遇到的一个问题是在数组中找到K个最大的数字。
我的第一个想法是使用部分选择排序(例如,从第一个元素扫描数组并保留两个变量用于所见的最低元素及其索引,并在数组末尾与该索引交换并继续这样做直到我们交换了K个元素并返回该数组中前K个元素的副本。
但是,这需要O(K*n)
次。如果我只是使用像Mergesort这样的高效排序方法对数组进行排序,那么只需要O(n*log(n))
时间对整个数组进行排序并返回K个最大数字。
在访谈期间讨论这两种方法是否足够好(比较输入的log(n)和K,并选择两者中较小的一种来计算K最大值)或假设我是安全的我期望为这个问题提供O(n)解决方案吗?
答案 0 :(得分:3)
存在O(n)
algorithm for finding the k'th smallest element,一旦拥有该元素,您只需扫描列表并收集相应的元素即可。它基于Quicksort,但其工作原理背后的原因是相当毛茸茸......还有一个更简单的变体,可能将在O(n)
中运行。 My answer to another question包含对此的简要讨论。
答案 1 :(得分:0)
这是对通过谷歌搜索找到的这个特定访谈问题的一般性讨论:
http://www.geeksforgeeks.org/k-largestor-smallest-elements-in-an-array/
至于你关于一般采访的问题,这可能在很大程度上取决于采访者。他们通常喜欢看你如何看待事物。因此,只要您能提出某种初步解决方案,您的面试官就可能会根据他们正在寻找的内容提出问题。
答案 2 :(得分:0)
K
很大(接近十亿),则您的部分选择几乎会产生O(n^2)
。我认为这完全取决于提出的问题的复杂性。
编辑:Aasmund Eldhuset的回答向您展示了如何实现O(n)
时间复杂度。
答案 3 :(得分:0)
如果你想找到K(因此,对于K = 5,你将获得五个结果 - 五个最高数字),那么你可以得到的最好的是O(n+klogn
) - 你可以在{{1}中建立prority队列然后调用O(n)
次k次。如果您正在寻找K最大数字,那么您可以通过pq.Dequeue()
快速修改来获取它 - 它被称为O(n)
。伪代码看起来像这样:(它是随机算法,平均时间约为k-th order statistics
,但最坏的情况是O(n)
)
O(n^2)
正如我所说,这个算法是QuickSortSelection(numbers, currentLength, k) {
if (currentLength == 1)
return numbers[0];
int pivot = random number from numbers array;
int newPivotIndex = partitionAroundPivot(numbers) // check quicksort algorithm for more details - less elements go left to the pivot, bigger elements go right
if ( k == newPivotIndex )
return pivot;
else if ( k < newPivotIndex )
return QuickSortSelection(numbers[0..newPivotIndex-1], newPivotIndex, k)
else
return QuickSortSelection(numbers[newPivotIndex+1..end], currentLength-newPivotIndex+1, k-newPivotIndex);
}
最坏的情况,因为枢轴是随机选择的(但运行时间〜^ ^ 2的概率类似于O(n^2)
)。你可以使用相同的运行时最坏情况转换它的确定性算法,例如1/2^n
作为一个支点 - 但它在实践中较慢(由于常数)。