第K个最大数字,为什么此运行时为O(n)而不是O(nlogn)

时间:2018-06-20 01:43:51

标签: algorithm runtime big-o

我在Leetcode中遇到了第k个最大数字问题

输入:[3,2,1,5,6,4]且k = 2,输出:5

建议的解决方案:

 public int findKthLargest(int[] nums, int k) {
    shuffle(nums);
    k = nums.length - k;
    int lo = 0;
    int hi = nums.length - 1;
    while (lo < hi) {
        final int j = partition(nums, lo, hi);
        if(j < k) {
            lo = j + 1;
        } else if (j > k) {
            hi = j - 1;
        } else {
            break;
        }
    }
    return nums[k];
}

private int partition(int[] a, int lo, int hi) {

    int i = lo;
    int j = hi + 1;
    while(true) {
        while(i < hi && less(a[++i], a[lo]));
        while(j > lo && less(a[lo], a[--j]));
        if(i >= j) {
            break;
        }
        exch(a, i, j);
    }
    exch(a, lo, j);
    return j;
}

private void exch(int[] a, int i, int j) {
    final int tmp = a[i];
    a[i] = a[j];
    a[j] = tmp;
}

private boolean less(int v, int w) {
    return v < w;
}

分区不采用O(n),而主函数中的while循环采用O(log n),因此应该为O(nlog n)吗?看起来它使用了Quicksort,但是quicksort的运行时是O(nlogn)。如果quicksort取O(n),这是有道理的,但没有意义。请帮助我了解发生了什么事?

1 个答案:

答案 0 :(得分:3)

这是具有平均/预期O(n)运行时间的随机算法。这是因为在随机调整输入列表后,我们通常具有足够好的枢轴,可以期望在每次分区函数调用之后,如果我们找不到目标,但我们会将列表(将在下一个搜索中)大致减少一半。这意味着,即使我们不走运并且不得不连续调用分区函数,我们也会不断将列表大小减小一半,因此,由于O(n)+ O(n / 2)+ O,平均运行时间仍然仅为O(n) (n / 4)+ ... + O(1)仍然是O(n)。