[Lintcode/Leetcode 题解] 狗狗家面试题:第 k 大元素(快速排序法)

2020-08-26 18:41:01 +08:00
 hakunamatata11

在数组中找到第 k 大的元素。(你可以交换数组中的元素的位置)

点此在线做题

样例 1:

输入:
n = 1, nums = [1,3,4,2]
输出:
4

样例 2:

输入:
n = 3, nums = [9,3,2,4,8]
输出:
4

[题解]

算法:快速选择算法

最容易想到的就是直接排序,返回第 k 大的值。时间复杂度是 O(nlogn),这里提供 O(n)的解法。

这题其实是快速排序算法的变体,在九章算法班中也有详细讲解。通过快速排序算法的 partition 步骤,可以将小于 pivot 的值划分到 pivot 左边,大于 pivot 的值划分到 pivot 右边,所以可以直接得到 pivot 的 rank 。从而缩小范围继续找第 k 大的值。

partition 步骤:

复杂度分析

设数组长度为 n

时间复杂度 O(n)

空间复杂度 O(1)

只需要快速选择游标的 O(1)额外空间。

public class Solution {
    /**
     * @param n: An integer
     * @param nums: An array
     * @return: the Kth largest element
     */
    public int kthLargestElement(int k, int[] nums) {
        int n = nums.length;
        // 为了方便编写代码,这里将第 k 大转换成第 k 小问题。
        k = n - k;
        return partition(nums, 0, n - 1, k);
    }
    public int partition(int[] nums, int start, int end, int k) {
        int left = start, right = end;
        int pivot = nums[left];

        while (left <= right) {
            while (left <= right && nums[left] < pivot) {
                left++;
            }
            while (left <= right && nums[right] > pivot) {
                right--;
            }
            if (left <= right) {
                swap(nums, left, right);
                left++;
                right--;
            }
        }

        // 如果第 k 小在右侧,搜索右边的范围,否则搜索左侧。
        if (k <= right) {
            return partition(nums, start, right, k);
        }
        if (k >= left) {
            return partition(nums, left, end, k);
        }
        return nums[k];
    }
    public void swap(int[] nums, int x, int y) {
        int temp = nums[x];
        nums[x] = nums[y];
        nums[y] = temp;
    }
}

更多题解参见

630 次点击
所在节点    推广
0 条回复

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/701682

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX