[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.

题目:输入一个未排序的整数数组,返回数组中第k大的数字。假设1<=k<=数组长度。

实现思路1:直接用Arrays.sort方法对数组升序排序,然后取index=n-k的元素就是最终结果(n是数组长度)。这种思路的时间复杂度是O(nlogn),空间复杂度是O(1)。如此简单无脑粗暴,题目应该不会只考察我们会不会使用Arrays.sort,所以还要想别的解法。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        if (nums == null) throw new IllegalArgumentException("argument is null");
        Arrays.sort(nums);
        return nums[nums.length - k];
    }
}

实现思路2:创建并维护一个容量是k的最小堆。逐个将元素加入最小堆,当堆容量大于k时删除堆首元素,这样当遍历完整个数组时,堆首元素就是我们要的最终结果。由于题目假设1<=k<=n,所以实现时不必考虑k=0的极端情况。这种思路的时间复杂度是O(nlogk),空间复杂度是O(k)。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        if (nums == null) throw new IllegalArgumentException("argument is null");
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        for (int i : nums) {
            pq.offer(i);
            if (pq.size() > k)
                pq.poll();
        }
        return pq.poll();
    }
}

实现思路3:Coursera上的普林斯顿大学课程Algorithms, Part I讲过Quick Select算法,这种算法是基于快速排序的划分过程选取第k小的元素。课程对这种算法讲解的非常详细,具体实现过程不再赘述,只需稍加修改即可完成本题。需要注意的几个地方:①题目求的是第k大的数字,因此划分过程要修改;②第k大的元素在降序排列数组中的index=k-1;③算法的最差时间复杂度是O(n^2),需要先对数组进行“洗牌”,但这也只是在概率上保证算法的平均时间复杂度达到O(n);④算法的时间复杂度是O(1)。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        if (nums == null) throw new IllegalArgumentException("argument is null");
        int lo = 0, hi = nums.length - 1;
        shuffle(nums);
        while (lo < hi) {
            int j = partition(nums, lo, hi);
            if (j > k - 1)
                hi = j - 1;
            else if (j < k - 1)
                lo = j + 1;
            else
                return nums[k - 1];
        }
        return nums[k - 1];
    }
    
    private int partition(int[] nums, int lo, int hi) {
        int x = nums[lo];
        int i = lo, j = hi + 1;
        while (true) {
            while (nums[++i] > x)
                if (i == hi) break;
            while (nums[--j] < x)
                if (j == lo) break;
            if (i >= j) break;
            swap(nums, i, j);
        }
        swap(nums, j, lo);
        return j;
    }
    
    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
    
    private void shuffle(int[] nums) {
        Random r = new Random();
        for (int i = 0; i < nums.length; i++) {
            int random = r.nextInt(i + 1);
            swap(nums, random, i);
        }
    }
}

参考资料:

https://www.coursera.org/learn/algorithms-part1/home/info

https://leetcode.com/problems/kth-largest-element-in-an-array/discuss/60294/Solution-explained

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值