[Week 1] LeetCode 215. Kth Largest Element in an Array

15 篇文章 0 订阅
13 篇文章 0 订阅

LeetCode 215. Kth Largest Element in an Array

问题描述:

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

输入示例:

Example 1:

Input: [3,2,1,5,6,4] and k = 2
Output: 5

Example 2:

Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4

Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.

题解:

对这个问题来讲,很容易想到先排序,但是这样做的时间复杂度是O(nlogn),因为我们只需要找到第K大的数即可(注意这里指的是排序后数组第K大的数而不是去重后的数组)。我们可以采用与快排一样的思路,先找一个pivot,然后将比它大的元素放它右边,小的放左边,然后看看pivot在数组中的index:

  1. index 等于 array‘s length - k,则返回它
  2. index 小于 array‘s length - k,则对pivot的右边进行相同操作
  3. index 大于 array‘s length - k,则对pivot的左边进行相同操作

Code:

递归版本:

void swap(vector<int>&nums, int i, int j) {
    int temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}

int helper(vector<int>& nums, int lo, int hi, int k) {
    if (lo == hi) return nums[lo];
    int pivot = nums[hi], l = lo, r = hi;
    while (l < r) {
        while (nums[l] <= pivot && l < r) ++l;
        while (nums[r] >= pivot && l < r) --r;
        swap(nums, l, r);
    }
    swap(nums, l, hi);
    if (l == nums.size() - k) return nums[l];
    else if (l < nums.size() - k) return helper(nums, l + 1, hi, k);
    else return helper(nums, lo, l - 1, k);
}

int findKthLargest(vector<int>& nums, int k) {
    return helper(nums, 0, nums.size() - 1, k);
}

非递归版本:

void swap(vector<int>&nums, int i, int j) {
    int temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}

int helper(vector<int>& nums, int lo, int hi) {
    if (lo == hi) return lo;
    int pivot = nums[hi], l = lo, r = hi;
    while (l < r) {
        while (nums[l] <= pivot && l < r) ++l;
        while (nums[r] >= pivot && l < r) --r;
        swap(nums, l, r);
    }
    swap(nums, l, hi);
    return l;
}

int findKthLargest(vector<int>& nums, int k) {
    int lo = 0, hi = nums.size() - 1;
    while (true) {
        int pivot = helper(nums, lo, hi);
        if (pivot == nums.size() - k) return nums[pivot];
        if (pivot < nums.size() - k) lo = pivot + 1;
        else hi = pivot - 1;
    }
}

复杂度分析
首先我们假设pivot找得很好,每次刚刚好都落在数组的中点,每次扫描一次截出来的数组,这样的话:
1. 数组大小为n,需n次比较
2. 数组大小为n/2,需n/2次比较
3. 数组大小为n/4,需n/4次比较
4. …
5. 数组大小为1,即找到目标元素
可以看到从第0趟到第logn趟,其比较次数是一个递减的等比数列,所以总复杂度我们可以用首项来表示,即O(n)。这里数组大小减小为1才能得出结果并不是必然的,即有机会在中间层就已经找到一个pivot刚好就是目标元素。

我们都知道quicksort最差会退化成O(n^2),当给定数组是有序时,这个算法最差也会退化至O(n^2),但对大部分情况来讲,只需要O(n),相比先排序,它不需要每趟都遍历整个完整的数组,也不需要进行合并的工作。同时,非递归版本比递归版本有更好的空间复杂度。

其它解法:

  • 将数组元素压入 priority_queue 中,其底层数据结构实现是大根堆,最后弹出k个元素即为第k大的元素,复杂度为O(nlogn),其复杂度主要在插入和弹出时对堆的结构的维护。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值