1. 程式人生 > >LeetCode 題解之 215. Kth Largest Element in an Array

LeetCode 題解之 215. Kth Largest Element in an Array

215. Kth Largest Element in an Array

題目描述和難度

  • 題目描述:

在未排序的陣列中找到第 k 個最大的元素。請注意,你需要找的是陣列排序後的第 k 個最大的元素,而不是第 k 個不同的元素。

示例 1:

輸入: [3,2,1,5,6,4] 和 k = 2
輸出: 5

示例 2:

輸入: [3,2,3,1,2,4,5,5,6] 和 k = 4
輸出: 4

說明:

你可以假設 k 總是有效的,且 1 ≤ k ≤ 陣列的長度。

思路分析

求解關鍵:這是一個常規問題,使用借用快速排序的 partition 的思想完成。關鍵在於理解 partition 的返回值,返回值是拉通了整個陣列的索引值,這一點是非常重要的,不要把問題想得複雜了。

  • partition 這個函式返回的是整個陣列的第 k 個最小元素(從 0 開始計算)。
  • 如果找第 k 個最小元素,即第 n - k 個最大元素。

例如:給定陣列為:[2,5,6,1,4,7] ,一共 6 個元素 找 k = 2,如果返回 4 ,就可以返回了。
給定陣列為:[2,5,6,1,4,7] ,一共 6 個元素 找 k = 2,如果返回 2 ,左邊的區間就可以不用看了。

參考解答

參考解答1:使用快速排序的 partition 的思想完成。

public class Solution2 {

    private static Random random = new
Random(System.currentTimeMillis()); public int findKthLargest(int[] nums, int k) { int len = nums.length; if (len == 0 || k > len) { throw new IllegalArgumentException("引數錯誤"); } // 轉換一下,這樣比較好操作 // 第 k 大元素的索引是 len - k int target = len - k; int
l = 0; int r = len - 1; while (true) { int i = partition(nums, l, r); if (i < target) { l = i + 1; } else if (i > target) { r = i - 1; } else { return nums[i]; } } } // 在區間 [left, right] 這個區間執行 partition 操作 private int partition(int[] nums, int left, int right) { // 在區間隨機選擇一個元素作為標定點(以下這兩行程式碼非必需) // 這一步優化非必需 if (right > left) { int randomIndex = left + 1 + random.nextInt(right - left); swap(nums, left, randomIndex); } int pivot = nums[left]; int l = left; for (int i = left + 1; i <= right; i++) { if (nums[i] < pivot) { l++; swap(nums, l, i); } } swap(nums, left, l); return l; } private void swap(int[] nums, int index1, int index2) { if (index1 == index2) { return; } int temp = nums[index1]; nums[index1] = nums[index2]; nums[index2] = temp; } }

參考解答2:使用最小堆,這個寫法是我最開始的寫法,有點死板。

public class Solution3 {

    public int findKthLargest(int[] nums, int k) {
        int len = nums.length;
        if (len == 0 || k > len) {
            throw new IllegalArgumentException("引數錯誤");
        }
        // 使用一個含有 k 個元素的最小堆
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(k, (a, b) -> a - b);
        for (int i = 0; i < k; i++) {
            priorityQueue.add(nums[i]);
        }
        for (int i = k; i < len; i++) {
            // 看一眼
            Integer topEle = priorityQueue.peek();
            // 只要當前遍歷的元素比堆頂元素大,堆頂出棧,遍歷的元素進去
            if (nums[i] > topEle) {
                priorityQueue.poll();
                priorityQueue.add(nums[i]);
            }
        }
        return priorityQueue.peek();
    }
}

參考解答3:最小堆更簡單的寫法。

public class Solution3 {

    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(k + 1, (a, b) -> (a - b));
        for (int num : nums) {
            priorityQueue.add(num);
            if(priorityQueue.size()==k+1){
                priorityQueue.poll();
            }
        }
        return priorityQueue.peek();
    }
}