77 第k大元素(Kth Largest Element)

1 题目

题目:第k大元素(Kth Largest Element)
描述:在数组中找到第 k 大的元素。你可以交换数组中的元素的位置。

lintcode题号——5,难度——medium

样例1:

输入:
k = 1
nums = [1,3,4,2]
输出:4
解释:第一大的元素是4

样例2:

输入:
k = 3
nums = [9,3,2,4,8]
输出:4
解释:第三大的元素是4。

2 解决方案

2.1 思路

  可以通过排序找到第k个数,排序的时间复杂度为O(n * log n)。该题还有更优的解法(quick select算法),可以通过快速排序的思路,但是只对数组做一半的快速排序,因为我们只需要关心存在结果的那一半部分的数组的排序就能够得到第k个数的位置。

2.2 时间复杂度

  每次找到并抛掉数组中不存在结果的区间的操作耗时为O(n),即在O(n)的耗时内,将T(n)规模的问题变为T(n/2)规模。

T(n) = T(n/2) + O(n)
     = T(n/4) + O(n/2) + O(n)
     = T(n/n) + O(2 + …… + n/4 + n/2 + n)
     = T(1) + O(2n)
     = O(n)

  所以总时间复杂度依然为O(n)。

2.3 空间复杂度

  空间复杂度为O(1)。

3 源码

细节:

  1. 使用quick select算法,快速排序的只递归一半,循环条件为left<=right。
  2. 第k大的数,即有序后的下标第k-1的数。

注意区别quick select与对向双指针,双指针只要left<right即可,quick select和快排由于要递归,令循环结束后left越过right,需要多走一步,把left、right作为边界递归子区间start-right和left-end,所以需要left<=right。

C++版本:

/**
* @param k: An integer
* @param nums: An array
* @return: the Kth largest element
*/
int kthLargestElement(int k, vector<int> &nums) {
    // write your code here
    int result = 0;
    if (nums.empty())
    {
        return result;
    }

    result = quickSelect(nums, 0, nums.size() - 1, k - 1); // 第k大的数,即下标第k-1的数

    return result;
}

int quickSelect(vector<int> & nums, int start, int end, int k)
{
    if (start == end)
    {
        return nums.at(start);
    }

    int left = start;
    int right = end;
    int key = nums.at(left + (right - left) / 2);
    while (left <= right) // 因为要对子数组递归,所以要取等号,令循环结束后left越过right
    {
        if (nums.at(left) > key) // 使用while需要添加判断条件left<=right,if则不用
        {
            left++;
            continue;
        }
        if (nums.at(right) < key)
        {
            right--;
            continue;
        }

        if (left <= right)
        {
            swap(nums.at(left++), nums.at(right--));
        }
    }

    if (k <= right && start <= right) // 注意right不能越界,k和start都小于right
    {
        return quickSelect(nums, start, right, k);
    }
    else if (left <= k && left <= end) // 注意left不能越界,k和end都大于left
    {
        return quickSelect(nums, left, end, k);
    }
    else
    {
        return nums.at(k);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值