Minimum Number of Flips to Make the Binary String Alternating
MedPrompt
You are given a binary string s. You are allowed to perform two types of operations on the string in any sequence:
- Type-1: Remove the character at the start of the string
sand append it to the end of the string. - Type-2: Pick any character in
sand flip its value, i.e., if its value is'0'it becomes'1'and vice-versa.
Return the minimum number of type-2 operations you need to perform such that s becomes alternating.
The string is called alternating if no two adjacent characters are equal.
- For example, the strings
"010"and"1010"are alternating, while the string"0100"is not.
Example 1:
Input: s = "111000"
Output: 2
Explanation: Use the first operation two times to make s = "100011".
Then, use the second operation on the third and sixth elements to make s = "101010".Example 2:
Input: s = "010"
Output: 0
Explanation: The string is already alternating.Example 3:
Input: s = "1110"
Output: 1
Explanation: Use the second operation on the second element to make s = "1010".
Constraints:
1 <= s.length <= 105s[i]is either'0'or'1'.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly simulates the problem statement. Since Type-1 operations (rotations) are free, we can try every possible rotation of the string s. For each of these n rotations, we calculate the minimum number of Type-2 operations (flips) needed to make it alternating. The final answer is the minimum value found across all rotations.
For any given string, there are two possible alternating patterns it can be converted to: one starting with '0' (e.g., "01010") and one starting with '1' (e.g., "10101"). We calculate the number of flips needed to achieve both patterns and take the smaller of the two. This process is repeated for all n rotations of the original string.
Algorithm
- Initialize
min_flipsto a very large value. - Let
nbe the length of the input strings. - Create a mutable version of the string, for example, using
StringBuilder. - Loop
ntimes, fromi = 0ton-1, to simulate each of thenpossible rotations.- In each iteration
i, we have a new rotated string. - Calculate the number of flips required to make this rotated string alternating. This requires two calculations:
flips1: Flips to match the pattern"0101...".flips2: Flips to match the pattern"1010...".
- To calculate
flips1andflips2, iterate fromj = 0ton-1and compare the character at each positionjwith the expected characters of the two target patterns. - Update
min_flipswith the minimum of its current value,flips1, andflips2. - Perform one rotation on the string builder (move the first character to the end) to prepare for the next iteration.
- In each iteration
- After the loop finishes,
min_flipswill hold the minimum number of flips required for any rotation.
Walkthrough
The algorithm iterates through all n possible cyclic shifts of the string s. In each iteration, it takes the current rotated string and computes the cost to transform it into an alternating string. The cost is the minimum of two values: the number of flips to match the "0101..." pattern and the number of flips to match the "1010..." pattern. The overall minimum cost found among all rotations is the result.
class Solution { public int minFlips(String s) { int n = s.length(); int minFlips = Integer.MAX_VALUE; StringBuilder sb = new StringBuilder(s); // Iterate through all n possible rotations for (int i = 0; i < n; i++) { // This is the i-th rotated string String current_s = sb.toString(); // Calculate flips for the two possible alternating patterns int flipsToPattern01 = 0; // for "0101..." int flipsToPattern10 = 0; // for "1010..." for (int j = 0; j < n; j++) { // Target pattern starting with '0' if (current_s.charAt(j) != (j % 2 == 0 ? '0' : '1')) { flipsToPattern01++; } // Target pattern starting with '1' if (current_s.charAt(j) != (j % 2 == 0 ? '1' : '0')) { flipsToPattern10++; } } minFlips = Math.min(minFlips, Math.min(flipsToPattern01, flipsToPattern10)); // Perform one rotation for the next iteration char firstChar = sb.charAt(0); sb.deleteCharAt(0); sb.append(firstChar); } return minFlips; }}Complexity
Time
O(N^2), where N is the length of the string. The outer loop runs N times for each rotation. The inner loop also runs N times to calculate the flips for the current rotation.
Space
O(N), where N is the length of the string. This space is used to store the mutable copy of the string (e.g., in a `StringBuilder`).
Trade-offs
Pros
It is a straightforward implementation of the problem's logic.
Easy to understand and reason about.
Cons
The time complexity of O(N^2) is too slow for the given constraints (N up to 10^5), leading to a 'Time Limit Exceeded' error on larger inputs.
It performs a lot of redundant calculations. The flip count for each rotation is calculated from scratch, while adjacent rotations share N-1 characters.
A more efficient approach uses a sliding window technique to avoid re-calculating flips for each rotation. The key idea is that any rotation of s is a contiguous substring of length n in the string s + s. By creating this doubled string, we can find the minimum flips for all rotations by sliding a window of size n across it.
We can pre-calculate the mismatches for the entire doubled string against two fixed alternating patterns ("0101..." and "1010..."). Then, as we slide our window, we can update the total mismatches for the window in constant time by subtracting the contribution of the character that leaves the window and adding the contribution of the character that enters. This reduces the overall time complexity from quadratic to linear.
Algorithm
- Let
nbe the length ofs. - Create a new string
s_doubleby concatenatingswith itself (s + s). This string of length2ncontains all possible rotations ofsas substrings of lengthn. - Create two helper arrays,
mismatches1andmismatches2, each of length2n.mismatches1[i]is 1 ifs_double[i]differs from the"0101..."pattern at indexi, 0 otherwise.mismatches2[i]is 1 ifs_double[i]differs from the"1010..."pattern at indexi, 0 otherwise.
- Initialize
flips1andflips2by summing the firstnelements ofmismatches1andmismatches2, respectively. This gives the flip counts for the original, un-rotated string. - Initialize
min_flips = min(flips1, flips2). - Iterate from
i = 1ton-1to slide a window of sizenacrosss_double.- In each step, update
flips1andflips2in O(1) time by subtracting the mismatch value of the character leaving the window and adding the mismatch value of the character entering the window. - The characters are
s_double[i-1](leaving) ands_double[i+n-1](entering). - After each update, update
min_flips = min(min_flips, flips1, flips2).
- In each step, update
- Return
min_flips.
Walkthrough
This optimized method avoids the O(N^2) complexity by recognizing that rotations can be viewed as a sliding window.
- Doubled String: We first create a string
s_doubleof length2nby appendingsto itself. Any cyclic shift ofswill appear as a substring of lengthnins_double. - Mismatch Arrays: We define two target alternating patterns that extend to length
2n:target1 = "0101..."andtarget2 = "1010...". We then create two boolean/integer arrays,mismatches1andmismatches2, wheremismatches1[i]is 1 ifs_double[i]does not matchtarget1[i], and similarly formismatches2. This takes O(N) time. - Sliding Window Sum: We calculate the number of flips for the first window (the original string
s) by summing the firstnelements of the mismatch arrays. Then, we slide the window one position at a time. For each slide, we update the flip counts in O(1) by subtracting the mismatch of the outgoing element and adding the mismatch of the incoming element. For each window, we find the minimum of the two flip counts and update our global minimum.
An important insight is that for any window starting at index i, the minimum flips will be min(current_flips1, current_flips2), where current_flips1 and current_flips2 are the sums of the mismatch arrays over that window. This holds true regardless of the parity of i because if the starting index i has a different parity, the roles of the two target patterns effectively swap, but the minimum of the two costs remains the same.
class Solution { public int minFlips(String s) { int n = s.length(); String s2 = s + s; int len2 = 2 * n; // Mismatches for target "0101..." (pattern1) int[] mismatches1 = new int[len2]; // Mismatches for target "1010..." (pattern2) int[] mismatches2 = new int[len2]; for (int i = 0; i < len2; i++) { if (s2.charAt(i) != (i % 2 == 0 ? '0' : '1')) { mismatches1[i] = 1; } if (s2.charAt(i) != (i % 2 == 0 ? '1' : '0')) { mismatches2[i] = 1; } } int flips1 = 0; // Flips for the current window vs pattern1 int flips2 = 0; // Flips for the current window vs pattern2 // Calculate flips for the initial window (the original string) for (int i = 0; i < n; i++) { flips1 += mismatches1[i]; flips2 += mismatches2[i]; } int minFlips = Math.min(flips1, flips2); // Slide the window across the doubled string for (int i = 1; i < n; i++) { // Update flip counts in O(1) flips1 = flips1 - mismatches1[i - 1] + mismatches1[i + n - 1]; flips2 = flips2 - mismatches2[i - 1] + mismatches2[i + n - 1]; minFlips = Math.min(minFlips, Math.min(flips1, flips2)); } return minFlips; }}Complexity
Time
O(N), where N is the length of the string. We iterate through the `2n` length string once to build mismatch arrays and then iterate `n` times for the sliding window, resulting in a linear time complexity.
Space
O(N), where N is the length of the string. This space is required to store the doubled string `s_double` and the two mismatch arrays.
Trade-offs
Pros
Optimal time complexity of O(N), making it very efficient for large inputs.
Solves the problem elegantly by transforming the rotation problem into a sliding window problem.
Cons
Requires O(N) extra space, which might be a consideration for extremely large N in a memory-constrained environment.
The logic, while efficient, is less direct than the brute-force approach and requires careful handling of indices and patterns.
Solutions
Solution
class Solution {public int minFlips(String s) { int n = s.length(); String target = "01"; int cnt = 0; for (int i = 0; i < n; ++i) { if (s.charAt(i) != target.charAt(i & 1)) { ++cnt; } } int ans = Math.min(cnt, n - cnt); for (int i = 0; i < n; ++i) { if (s.charAt(i) != target.charAt(i & 1)) { --cnt; } if (s.charAt(i) != target.charAt((i + n) & 1)) { ++cnt; } ans = Math.min(ans, Math.min(cnt, n - cnt)); } return ans; }}class Solution {public: int minFlips(string s) { int n = s.size(); string target = "01"; int cnt = 0; for (int i = 0; i < n; ++i) { if (s[i] != target[i & 1]) { ++cnt; } } int ans = min(cnt, n - cnt); for (int i = 0; i < n; ++i) { if (s[i] != target[i & 1]) { --cnt; } if (s[i] != target[(i + n) & 1]) { ++cnt; } ans = min({ans, cnt, n - cnt}); } return ans; }};class Solution: def minFlips(self, s: str) -> int: n = len(s) target = "01" cnt = sum(c != target[i & 1] for i, c in enumerate(s)) ans = min(cnt, n - cnt) for i in range(n): cnt -= s[i] != target[i & 1] cnt += s[i] != target[(i + n) & 1] ans = min(ans, cnt, n - cnt) return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.