Medium草稿★★★★O(n) 時間 · O(1) 空間
HeapPriority QueueQuick SelectSorting
Patterns⚡ 快速選擇⛰️ 堆・Top-K🔢 排序後處理
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

215Kth Largest Element in an ArrayHeap / Priority QueueMediumHeap / Priority Queue

給定一個整數陣列 nums 和整數 k,回傳陣列中第 k 大的元素。注意是排序後第 k 大,不是第 k 個不同的元素。要求設計不排序的演算法。

Example:

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

Intuition

TIP

核心思路:第 K 大問題的兩大武器——Min Heap (O(n log k)) 或 Quick Select (平均 O(n))。

Approaches

1. Min Heap — O(n log k) / O(k)
  • Idea: 維護大小為 k 的 Min Heap,遍歷所有元素,堆頂即第 k 大
  • Time: O(n log k)
  • Space: O(k)
class Solution {
    fun findKthLargest(nums: IntArray, k: Int): Int {
        val minHeap = PriorityQueue<Int>()

        for (num in nums) {
            minHeap.offer(num)
            if (minHeap.size > k) {
                minHeap.poll()
            }
        }

        return minHeap.peek()
    }
}
⭐ 2. Quick Select — O(n) avg / O(1)
  • Idea: 隨機選 pivot 做 partition,根據 pivot 位置決定只往左或右遞迴,平均只需 O(n)
  • Time: 平均 O(n),最壞 O(n^2)(加隨機化可降低最壞情況機率)
  • Space: O(1)
class Solution {
    fun findKthLargest(nums: IntArray, k: Int): Int {
        val targetIdx = nums.size - k
        return quickSelect(nums, 0, nums.size - 1, targetIdx)
    }

    private fun quickSelect(nums: IntArray, left: Int, right: Int, target: Int): Int {
        val pivotIdx = left + (Math.random() * (right - left + 1)).toInt()
        val pivot = nums[pivotIdx]
        nums[pivotIdx] = nums[right].also { nums[right] = nums[pivotIdx] }

        var i = left
        for (j in left until right) {
            if (nums[j] <= pivot) {
                nums[i] = nums[j].also { nums[j] = nums[i] }
                i++
            }
        }
        nums[i] = nums[right].also { nums[right] = nums[i] }

        return when {
            i == target -> nums[i]
            i < target -> quickSelect(nums, i + 1, right, target)
            else -> quickSelect(nums, left, i - 1, target)
        }
    }
}
Note: Sorting

最直觀的做法,排序後直接取。

class Solution {
    fun findKthLargest(nums: IntArray, k: Int): Int {
        nums.sort()
        return nums[nums.size - k]
    }
}
  • Time: O(n log n)
  • Space: O(1)O(n) 取決於排序實作

🔑 Takeaways

Ladders 看全部 →

⛰️

Top-K / 第 K 大

quickselect、堆、桶排序各擅勝場。

  1. 1
  2. 2#347Top K Frequent ElementsMedium前 K 高頻:桶排序 / 堆
  3. 3#973K Closest Points to OriginMedium最近 K 個點:以距離為鍵的堆
  4. 4#703Kth Largest Element in a StreamEasy資料流中第 K 大:維護大小為 k 的堆