狗狗家面试题:第 k 大元素(快速排序法)

本文介绍了一种在O(n)时间内找到数组中第k大元素的算法——快速选择算法,它是快速排序的一种变体。通过partition过程,算法能有效确定pivot的排名,并缩小搜索范围。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在数组中找到第 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步骤:

  • 令left = start,right = end,pivot = nums[left]。
  • 当nums[left] < pivot时,left指针向右移动。
  • 当nums[right] > pivot时,right指针向左移动。
  • 交换两个位置的值,right指针左移,left指针右移。
  • 直到两指针相遇,否则回到第2步。
    每次partition后根据pivot的位置,寻找下一个搜索的范围。

复杂度分析

设数组长度为n

时间复杂度O(n)

  • 对一个数组进行partition的时间复杂度为O(n)。
  • 分治,选择一边继续进行partition。
  • 所以总的复杂度为T(n) = T(n / 2) + O(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;
    }
}

更多题解参见


评论区可领取LintCode 7 天 VIP,输入优惠码9C06EB即可领取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值