Medium草稿★★★★★O(n) 時間 · O(1) 空間
GreedyHash MapTwo Pointers
Patterns↔️ 雙指針🪙 貪心#️⃣ 雜湊
尚未複習過

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

763Partition LabelsGreedyMediumGreedy

給定一個字串 s,將它分割成盡可能多的片段,使得每個字母最多只出現在一個片段中。回傳每個片段的長度列表。

Example:

Input: s = “ababcbacadefegdehijhklij” Output: [9,7,8]

Intuition

TIP

記錄每個字元的最後出現位置,遍歷時維護當前片段的邊界,邊界到達時切割。

Approaches

1. Brute Force (merge intervals) — O(n + k log k) / O(k)
  • Idea: 為每個字元建立 [首次出現, 最後出現] 的區間,然後做區間合併。
  • Time: O(n + k log k),k 為不同字元數
  • Space: O(k)
class Solution {
    fun partitionLabels(s: String): List<Int> {
        val first = IntArray(26) { -1 }
        val last = IntArray(26) { -1 }
        for (i in s.indices) {
            val c = s[i] - 'a'
            if (first[c] == -1) first[c] = i
            last[c] = i
        }
        val intervals = mutableListOf<IntArray>()
        for (i in 0 until 26) {
            if (first[i] != -1) intervals.add(intArrayOf(first[i], last[i]))
        }
        intervals.sortBy { it[0] }
        val result = mutableListOf<Int>()
        var start = intervals[0][0]
        var end = intervals[0][1]
        for (i in 1 until intervals.size) {
            if (intervals[i][0] <= end) {
                end = maxOf(end, intervals[i][1])
            } else {
                result.add(end - start + 1)
                start = intervals[i][0]
                end = intervals[i][1]
            }
        }
        result.add(end - start + 1)
        return result
    }
}
⭐ 2. Greedy (Single Pass) — O(n) / O(1)
  • Idea: 預處理每個字元的最後位置後,一次遍歷即可完成切割。
  • Time: O(n)
  • Space: O(1)(26 個字元的陣列為常數)
class Solution {
    fun partitionLabels(s: String): List<Int> {
        val lastIndex = IntArray(26)
        for (i in s.indices) {
            lastIndex[s[i] - 'a'] = i
        }
        val result = mutableListOf<Int>()
        var start = 0
        var end = 0
        for (i in s.indices) {
            end = maxOf(end, lastIndex[s[i] - 'a'])
            if (i == end) {
                result.add(end - start + 1)
                start = i + 1
            }
        }
        return result
    }
}

🔑 Takeaways