Medium草稿★★★★O(n) 時間 · O(1) 空間
ArrayTwo PointersSorting
Patterns↔️ 雙指針🔢 排序後處理
尚未複習過

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

75Sort ColorsArrays & HashingMediumArrays & Hashing

給定陣列 nums,其中只包含 0、1、2(代表紅、白、藍),原地排序使得相同顏色相鄰,順序為 0、1、2。不能使用內建排序函式。

Example:

Input: nums = [2,0,2,1,1,0] Output: [0,0,1,1,2,2]

Intuition

TIP

核心思路:Dutch National Flag(荷蘭國旗問題)——用三個指標將陣列分為三個區域:0 區、1 區、2 區。

Approaches

1. Two Passes (counting sort) — O(n) / O(1)
  • Idea: 第一次遍歷統計 0、1、2 的數量,第二次遍歷按順序填入
  • Time: O(n) - 兩次遍歷
  • Space: O(1) - 只用三個計數器
class Solution {
    fun sortColors(nums: IntArray) {
        val count = IntArray(3)
        for (num in nums) count[num]++
        var idx = 0
        for (color in 0..2) {
            repeat(count[color]) {
                nums[idx++] = color
            }
        }
    }
}
⭐ 2. Dutch National Flag (single pass) — O(n) / O(1)
  • Idea: 三指標分區——lo 追蹤 0 的右邊界,hi 追蹤 2 的左邊界,mid 掃描
  • Time: O(n) - 一次遍歷
  • Space: O(1) - 原地交換
class Solution {
    fun sortColors(nums: IntArray) {
        var lo = 0
        var mid = 0
        var hi = nums.lastIndex

        while (mid <= hi) {
            when (nums[mid]) {
                0 -> {
                    nums[mid] = nums[lo].also { nums[lo] = nums[mid] }
                    lo++
                    mid++
                }
                1 -> {
                    mid++
                }
                2 -> {
                    nums[mid] = nums[hi].also { nums[hi] = nums[mid] }
                    hi--
                    // mid 不動,因為交換過來的值還沒檢查
                }
            }
        }
    }
}

WARNING

注意:遇到 2 交換後 mid 不能前進,因為從 hi 換過來的值還未被檢查。遇到 0 交換後 mid 可以前進,因為 lo 左邊只可能是 0 或已處理的 1。

🔑 Takeaways