Medium草稿★★★★★O(n) 時間 · O(1) 空間
StringHash TableGreedy
Patterns🪙 貪心#️⃣ 雜湊
尚未複習過

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

2405Optimal Partition of StringArrays & HashingMediumArrays & Hashing

給定字串 s,將其分割成最少的子字串,使每個子字串中的字元都不重複。回傳最少的分割數量。

Example:

Input: s = “abacaba” Output: 4 (“ab”, “ac”, “ab”, “a”)

Intuition

TIP

核心思路:Greedy——盡可能讓每個子字串最長(包含最多不重複字元)。遇到重複字元時就開始新的子字串。

Approaches

1. HashSet Greedy — O(n) / O(26)
  • Idea: 用 HashSet 記錄當前子字串的字元,遇到重複就清空並計數
  • Time: O(n) - 一次遍歷
  • Space: O(26) = O(1) - 最多 26 個字母
class Solution {
    fun partitionString(s: String): Int {
        val seen = HashSet<Char>()
        var count = 1

        for (c in s) {
            if (c in seen) {
                count++
                seen.clear()
            }
            seen.add(c)
        }

        return count
    }
}
⭐ 2. Bitmask Greedy — O(n) / O(1)
  • Idea: 用 26-bit 整數取代 HashSet,每個 bit 代表一個字母是否出現過
  • Time: O(n) - 一次遍歷
  • Space: O(1) - 一個整數
class Solution {
    fun partitionString(s: String): Int {
        var mask = 0
        var count = 1

        for (c in s) {
            val bit = 1 shl (c - 'a')
            if (mask and bit != 0) {
                count++
                mask = 0
            }
            mask = mask or bit
        }

        return count
    }
}

WARNING

初始化 count = 1 而非 0,因為即使沒有重複,字串本身就是一個子字串。最後一段子字串不會觸發 count++,所以初始值要從 1 開始。

🔑 Takeaways