对数字的数字列表进行排序并获得第一个和第二个最大的数字将为您提供最佳的O(n * log n)
时间复杂度(假设您将使用Quick Sort)。
如果您将使用另一种方法,您可以获得更好的性能:分区(重新排序)您的数组(如快速排序),因此您将拥有一个将数组分为两部分的枢轴值:小于枢轴的那些在左边部分(左子数组),较大的在右边部分(右子数组)。检查枢轴的索引:
- 如果它等于数字数组的大小 - 2,则它是第二大元素(第一个大元素在它旁边,在右侧子数组中);
- 如果枢轴的索引小于数字数组的大小减2,则对右子数组重复分区;
- 如果枢轴的索引大于数字数组的大小减2,则对左子数组重复分区;
在某些时候,您的枢轴将是数组末尾的第二个元素,这意味着它是第二大元素,并且最大的数字位于数组的末尾(因为您获取枢轴的方式)。时间复杂度比快速排序要好,因为在每个分区之后,您只分区一个子数组,而不是两个子数组。
您可以扩展这种方法,不仅可以获得第 1 位和第 2 位最大的数字,还可以获得第 k(任意最高)数字,不仅是最大的,而且也是最小的。
看看我几天前写的一段代码:
public Long selectKthElement(int left, int right, int k, Type type) {
int med = partitionIt(left, right);
if ((type.equals(Type.Smallest) && med == k - 1) || (type.equals(Type.Largest) && med == nElems - k)) {
return theArray[med];
} else if (type.equals(Type.Smallest) && med > k || type.equals(Type.Largest) && med > nElems - k) {
return selectKthElement(left, med - 1, k, type);
} else if (type.equals(Type.Smallest) && med < k || type.equals(Type.Largest) && med < nElems - k){
return selectKthElement(med + 1, right, k, type);
} else {
// impossible case, but the source code won't compile w/o the else
return null;
}
}
这theArray
是一个数字的数组,partitionIt
方法对数组进行重新排序并返回中位数的索引,您可以自己弄清楚如何编写它的实现,或者通过网络搜索。