数组中第K大的数字

1 数组第K大

LeetCode215 数组中的第K个最大元素。给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例1:

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

输出: 5

示例2:

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

输出: 4

我们在堆部分分析过这个问题,这里看看如何基于快速排序来做,这个题目出现的频率非常高,甚至在很多时候,面试官直接要求基于快速排序来解决这个问题。而且我们要直接改造一下上面的快排来解决,而不是另起炉灶,只有这样平时的练习才有效果。
为什么能用快速排序来解决呢?我们还是看上面排序的序列:{26,53,48,15,13,48,32,15}
我们第一次选择了26为哨兵,进行一轮的排序过程为:

数组中第K大的数字_第1张图片

上面红框位置表示当前已经被赋值给了pivot或者其他位置,可以空出来放移动来的新元素了。我们可以看到26最终被放到了属于自己的位置上,不会再变化,而26的左右两侧可以分别再进行排序。
这里还有一个关键信息, 我们可以知道26的索引为3,所以递增排序之后26一定是第4大的元素 。这就是解决本问题的关键,既然知道26是第4大,那如果我要找第2大,一定是要到右边找。如果要找第6大,一定要到左边找(当然,如果降序排序就反过来了),而不需要的那部分就不用管了。这就是为什么能用快速排序解决这个问题。

int quickselect(int[] nums, int l, int r, int k) {
    if (l == r) return nums[k];
    int x = nums[l], i = l - 1, j = r + 1;
    while (i < j) {
        do i++; while (nums[i] < x);
        do j--; while (nums[j] > x);
        if (i < j){
            int tmp = nums[i];
            nums[i] = nums[j];
            nums[j] = tmp;
        }
    }
    if (k <= j) return quickselect(nums, l, j, k);
    else return quickselect(nums, j + 1, r, k);
}
public int findKthLargest(int[] _nums, int k) {
    int n = _nums.length;
    return quickselect(_nums, 0, n - 1, n - k);
}

我们尽量能套用已经练习过的代码,否则核心逻辑都要考虑相反情况,会让我们面试时现场写变得非常困难。

你可能感兴趣的:(算法,排序算法,数据结构)