1888. Minimum Number of Flips to Make The Binary String Alternating - Explanation

Problem Link



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Sliding Window Technique - Efficiently processing subarrays/substrings by maintaining a window of fixed or variable size
  • String Manipulation - Working with rotations and pattern matching in strings
  • Modular Arithmetic - Using mod operator to simulate circular array traversal
  • Dynamic Programming - Tracking state transitions as elements shift positions

1. Brute Force

Intuition

An alternating string is either "010101..." or "101010...". The type-1 operation (moving first character to end) lets us try all possible rotations of the string. For each rotation, we count how many flips are needed to match either target pattern.

We generate both alternating patterns of length n, then for each of the n possible rotations, compute the difference count against both patterns and track the minimum.

Algorithm

  1. Build two target patterns: alt1 starting with '0' and alt2 starting with '1'.
  2. For each rotation index i from 0 to n-1:
    • Create the rotated string by moving the first i characters to the end.
    • Count mismatches with both alt1 and alt2.
    • Update the minimum flip count.
  3. Return the minimum found.
class Solution:
    def minFlips(self, s: str) -> int:
        res = n = len(s)
        alt1, alt2 = [], []
        for i in range(n):
            alt1.append("0" if i % 2 == 0 else "1")
            alt2.append("1" if i % 2 == 0 else "0")

        def diff(A, B):
            cnt = 0
            for i in range(n):
                cnt += 1 if (A[i] != B[i]) else 0
            return cnt

        for i in range(n):
            newS = s[i:] + s[:i]
            res = min(res, min(diff(alt1, newS), diff(alt2, newS)))
        return res

Time & Space Complexity

  • Time complexity: O(n2)O(n ^ 2)
  • Space complexity: O(n)O(n)

2. Brute Force (Space Optimized)

Intuition

Instead of creating explicit rotated strings, we can iterate circularly through the original string using modular arithmetic. For each starting position, we walk through all n characters and count mismatches against both alternating patterns on the fly.

This saves the O(n) space needed to store rotated strings while maintaining the same logic: try every rotation and count flips needed for both target patterns.

Algorithm

  1. For each starting position i:
    • Initialize counters for mismatches against "010..." and "101...".
    • Walk through n characters using modular indexing (i + k) % n.
    • Toggle the expected character as we go.
    • Track the minimum between both pattern mismatches.
  2. Return the overall minimum.
class Solution:
    def minFlips(self, s: str) -> int:
        n = res = len(s)

        for i in range(n):
            start_0 = 1 if s[i] != '0' else 0
            start_1 = 1 if s[i] != '1' else 0
            c = '0'
            j = (i + 1) % n
            while j != i:
                start_1 += 1 if s[j] != c else 0
                start_0 += 1 if s[j] == c else 0
                c = '0' if c == '1' else '1'
                j = (j + 1) % n

            res = min(res, min(start_1, start_0))
        return res

Time & Space Complexity

  • Time complexity: O(n2)O(n ^ 2)
  • Space complexity: O(1)O(1) extra space.

3. Sliding Window

Intuition

Concatenating the string with itself (s + s) simulates all rotations. A window of size n sliding over this doubled string represents each rotation. We can maintain mismatch counts incrementally: add the new character's contribution when expanding the window, and remove the old character's contribution when shrinking.

This transforms the O(n^2) brute force into O(n) by avoiding recalculation of the full difference for each rotation.

Algorithm

  1. Double the string: s = s + s.
  2. Build alternating patterns of length 2n.
  3. Use two pointers l and r to maintain a window of size n:
    • As r expands, update diff1 and diff2 based on mismatches at position r.
    • When window exceeds size n, remove contribution from position l and advance l.
    • When window is exactly size n, record the minimum of diff1 and diff2.
  4. Return the minimum.
class Solution:
    def minFlips(self, s: str) -> int:
        n = len(s)
        s = s + s
        alt1, alt2 = [], []
        for i in range(len(s)):
            alt1.append("0" if i % 2 == 0 else "1")
            alt2.append("1" if i % 2 == 0 else "0")

        res = len(s)
        diff1, diff2 = 0, 0
        l = 0

        for r in range(len(s)):
            if s[r] != alt1[r]:
                diff1 += 1
            if s[r] != alt2[r]:
                diff2 += 1

            if r - l + 1 > n:
                if s[l] != alt1[l]:
                    diff1 -= 1
                if s[l] != alt2[l]:
                    diff2 -= 1
                l += 1

            if r - l + 1 == n:
                res = min(res, diff1, diff2)

        return res

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

4. Sliding Window (Space Optimized)

Intuition

We can avoid storing the doubled string and alternating patterns by computing expected characters on the fly. By tracking what character position r should have (toggling between '0' and '1'), we update mismatch counts directly.

Using modular indexing s[r % n] simulates the doubled string. We track the expected starting character for both window boundaries and toggle as we slide.

Algorithm

  1. Initialize difference counters and window boundaries.
  2. For r from 0 to 2n - 1:
    • Compute expected character at position r for pattern starting with '0'.
    • Update both mismatch counts based on whether s[r % n] matches.
    • If window exceeds size n, remove contribution from s[l] and advance l.
    • When window equals size n, update minimum.
  3. Toggle expected characters as window slides.
class Solution:
    def minFlips(self, s: str) -> int:
        res = n = len(s)
        diff1 = diff2 = l = 0

        rstart_0 = lstart_0 = '0'

        for r in range(2 * n):
            if s[r % n] != rstart_0:
                diff1 += 1
            if s[r % n] == rstart_0:
                diff2 += 1

            if r - l + 1 > n:
                if s[l] != lstart_0:
                    diff1 -= 1
                if s[l] == lstart_0:
                    diff2 -= 1
                l += 1
                lstart_0 = '1' if lstart_0 == '0' else '0'

            if r - l + 1 == n:
                res = min(res, diff1, diff2)

            rstart_0 = '1' if rstart_0 == '0' else '0'

        return res

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(1)O(1) extra space.

5. Dynamic Programming

Intuition

First, count mismatches for the original string against pattern "1010...". The mismatch count for "0101..." is simply n - start_1 since every position either matches one pattern or the other.

For odd-length strings, rotating changes parity. After one rotation, positions that needed a '0' now need a '1' and vice versa. We can compute the new mismatch counts by swapping and adjusting based on the character that moved from front to back.

Algorithm

  1. Count initial mismatches (start_1) against pattern "101...".
  2. Compute start_0 = n - start_1 for pattern "010...".
  3. If n is even, rotations do not change the answer, so return min(start_0, start_1).
  4. For odd n, simulate each rotation:
    • Swap dp0 and dp1 (parity flip).
    • Adjust counts based on the character that rotated.
    • Track minimum across all rotations.
class Solution:
    def minFlips(self, s: str) -> int:
        start_1 = 0
        for i in range(len(s)):
            if i & 1:
                start_1 += s[i] == "1"
            else:
                start_1 += s[i] == "0"

        start_0 = len(s) - start_1
        ans = min(start_0, start_1)
        if len(s) % 2 == 0:
            return ans

        dp0, dp1 = start_0, start_1
        for c in s:
            dp0, dp1 = dp1, dp0
            if c == "1":
                dp0 += 1
                dp1 -= 1
            else:
                dp0 -= 1
                dp1 += 1
            ans = min(dp0, dp1, ans)
        return ans

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(1)O(1) extra space.

Common Pitfalls

Forgetting That Rotations Only Matter for Odd-Length Strings

For even-length strings, rotating the string does not change the number of flips needed because the parity of each position remains the same after a full rotation cycle. The optimization to skip rotations when n % 2 == 0 is critical for both correctness and performance. Without this check, you might perform unnecessary work or miss that the initial comparison already gives the optimal answer.

Incorrectly Handling the Doubled String in Sliding Window

When using the sliding window approach with s + s, you must build alternating patterns of length 2n, not n. If you only build patterns of length n and try to index beyond, you will get index-out-of-bounds errors or incorrect mismatch counts. Additionally, when the window slides, you must properly remove the contribution of the leftmost character before adding the new rightmost character.

Confusing Which Pattern Tracks Which Mismatches

The two patterns "010101..." and "101010..." are complementary. If a position matches one pattern, it mismatches the other. When computing both diff counts simultaneously, ensure you are consistent: if s[r] != alt1[r], increment diff1; if s[r] != alt2[r], increment diff2. Mixing up which count corresponds to which pattern will produce incorrect minimum flip counts.