Description

給定二進位字串 s,可以執行兩種操作:

  • Type-1: 移除最左邊的字元並加到最右邊
  • Type-2: 翻轉任一位元(0->1 或 1->0)

回傳使字串變成交替字串(“010101…” 或 “101010…")所需的最少 Type-2 操作次數(Type-1 可以做任意次)。

Example:

Input: s = “111000” Output: 2(先做 Type-1 兩次得到 “100011”,再翻轉兩位得到 “101010”)

Intuition#

核心思路:把字串複製一份接在後面模擬循環旋轉,然後用固定大小為 n 的滑動視窗,計算每個旋轉版本與兩種交替模式的差異數。

  • Type-1 操作就是循環旋轉,把 s 拼接成 s + s 後,任何長度 n 的子字串就是一種旋轉結果
  • 目標只有兩種:"010101...""101010..."
  • 對每個旋轉版本,計算需要幾次 Type-2 翻轉才能匹配目標

Approaches#

1: 模擬所有旋轉#

  • 概念: 嘗試每種旋轉,對每種旋轉計算與兩個目標的差異數
  • 時間複雜度: O(n²) - n 種旋轉各掃描 n 個字元
  • 空間複雜度: O(n) - 旋轉後的字串
模擬程式碼
class Solution {
    fun minFlips(s: String): Int {
        val n = s.length
        var result = n
        for (rot in 0 until n) {
            val rotated = s.substring(rot) + s.substring(0, rot)
            var diff0 = 0 // 與 "0101..." 的差異
            var diff1 = 0 // 與 "1010..." 的差異
            for (i in rotated.indices) {
                val expected0 = if (i % 2 == 0) '0' else '1'
                if (rotated[i] != expected0) diff0++
                else diff1++
            }
            result = minOf(result, diff0, diff1)
        }
        return result
    }
}

⭐2: 字串拼接 + Fixed Sliding Window#

  • 概念: 將 s + s 作為基礎,預計算每個位置與兩種交替模式的差異,用大小為 n 的滑動視窗維護差異計數
  • 時間複雜度: O(n) - 一次遍歷拼接後的字串
  • 空間複雜度: O(n) - 拼接字串
class Solution {
    fun minFlips(s: String): Int {
        val n = s.length
        val doubled = s + s
        var diff0 = 0 // 與 "010101..." 不同的位數
        var diff1 = 0 // 與 "101010..." 不同的位數
        var result = n

        for (i in doubled.indices) {
            // 位置 i 對應交替模式的期望值
            val expected0 = if (i % 2 == 0) '0' else '1'
            if (doubled[i] != expected0) diff0++
            else diff1++ // expected1 與 expected0 互補

            // 移除左邊離開視窗的字元
            if (i >= n) {
                val leftExpected0 = if ((i - n) % 2 == 0) '0' else '1'
                if (doubled[i - n] != leftExpected0) diff0--
                else diff1--
            }

            // 視窗大小達到 n 時更新結果
            if (i >= n - 1) {
                result = minOf(result, diff0, diff1)
            }
        }
        return result
    }
}

交替模式的判斷用 i % 2(全域位置),不是視窗內的相對位置。因為 s + s 中拼接後位置的奇偶性自然對應正確的交替模式。

🔑 Takeaways#

  • Pattern: 字串拼接模擬循環 + 固定大小滑動視窗
  • 關鍵技巧: s + s 是處理循環旋轉問題的標準技巧;同時追蹤兩種目標模式的差異數,避免重複計算