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

你可能感兴趣的:(LeetCode)