1888. Minimum Number of Flips to Make the Binary String Alternating
Problem Description
The given LeetCode problem involves operations on a binary string, which is a string composed solely of '0's and '1's. The objective is to make the string "alternating", which means no two consecutive characters in the string are the same. There are two types of operations that can be used to achieve this:
- Type-1: Remove the first character of the string and append it to the end. This is effectively a cyclic permutation of the string.
- Type-2: Flip a character in the string from '0' to '1' or from '1' to '0'.
The challenge is to determine the minimum number of Type-2 operations (flips) required to make the string alternating. We don't need to worry about the number of Type-1 operations since the question only asks for the count of Type-2 operations.
Intuition
The intuition behind the solution comes from observing patterns within an alternating string. Consider the two alternating patterns for a binary string: "010101..." and "101010...". Any valid alternating binary string can be transformed into either of these two patterns with Type-2 operations.
The key insight is to simulate the operations to move towards one of these patterns. Here's how the solution approach works:
-
Calculate the number of flips required to convert the current string into the "010101..." pattern. This is done by comparing each character in the binary string to the expected character in the "01" pattern. Keep count of mismatches.
-
Calculate the number of flips required for the "101010..." pattern. This is simply the length of the string minus the number of flips for "010101..." because every place that matches one pattern mismatches the other and vice versa.
-
Consider the effect of Type-1 operations. Since Type-1 operations are just cyclic permutations, simulate this by moving through the string and adjusting the mismatch count as if the first character is moved to the end, one by one.
-
At each step, recalculate the number of flips needed, taking into account the updated first character. Repeat this for the entire string length and track the minimum number of flips found.
-
The outcome is the minimum of these recalculated flip counts.
This algorithm works because it efficiently combines the permissibility of Type-1 operations to rearrange the string (without actually doing it) with the direct calculation of Type-2 operations required to achieve the pattern.
Learn more about Greedy, Dynamic Programming and Sliding Window patterns.
Solution Approach
The approach to solving this problem is as follows:
-
First, we need initial counts of mismatches for both alternating patterns for the input string
s
. This can be achieved by iterating over the string and checking each character if it matches the expected character in the pattern "010101...". -
To implement this, we compare each character in
s
with the expected character in the pattern. For example,c
should matchtarget[i & 1]
, where&
is the bitwise AND operator, used here to alternate between0
and1
as we move along the string. -
We keep a running count
cnt
of how many characters do not match the expected "01" pattern. Since for an alternating string of lengthn
, the other pattern is just the inverse, the count for the other pattern isn - cnt
. -
We then initialize the answer
ans
to be the minimum ofcnt
andn - cnt
because we have the choice to convert to either pattern. -
Next, we simulate Type-1 operations without actually permuting the string. We iterate over the string once again and, for each character, update the mismatch count
cnt
for the two patterns by considering that the first character is moved to the end. Specifically, we will reducecnt
by one if the first character differs from the expected character in the current position and adjustcnt
considering it's now at the end of the string. This effectively simulates a cyclic shift to the left by one position. -
After each simulated cyclic shift, we update
ans
with the minimum of the currentans
, currentcnt
, andn - cnt
, which keeps track of the minimum number of flips required after each simulated Type-1 operation. -
After the loop,
ans
contains the minimum number of flips required to make the string alternating.
In terms of algorithms and data structures, this solution employs a greedy counting approach, where we greedily count mismatches against an expected pattern and use properties of bitwise operations to efficiently alternate between '0' and '1'. The solution also leverages in-place updates to minimize space complexity; no additional data structures are needed beyond simple variables for keeping track of counts and the final answer.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's illustrate the solution approach with a small example. Suppose the input binary string is s = "0011"
. We are to find out the minimum number of flips (Type-2 operations) to make the string alternating ("0101"
or "1010"
).
-
We start by calculating the number of flips needed for the pattern starting with
0
("0101"
). As we scans
, we notice:s[0]
= '0', no flip needed (matches "0101").s[1]
= '0', flip needed (does not match "0101", should be '1').s[2]
= '1', no flip needed (matches "0101").s[3]
= '1', flip needed (does not match "0101", should be '0').
Therefore, we have 2 mismatches for the
"0101"
pattern, which meanscnt = 2
. -
For the pattern starting with
1
("1010"
), we find that we also have 2 mismatches, because it is just the inverse of the other pattern, son - cnt = 2
. -
We initialize our answer
ans = min(cnt, n - cnt)
, which in this case ismin(2, 2) = 2
. -
Now, we simulate the Type-1 operations. We cyclically move the first character to the end and update the flip count. After the first shift, our string becomes "
0110
":s[1]
was '0', and now it's in the second position where it should be '1', socnt
increases to 3.s[0]
was '0', and now it's in the last position where it should be '0', so no change incnt
.
-
We then update
ans
withmin(ans, cnt, n - cnt)
. Sincecnt
increased, we havemin(2, 3, 2)
, soans
remains2
. -
We continue the simulation for two more shifts:
- After second shift to "
1100
",cnt
would decrease since the first '1' at the third position matches, and the last '0' still matches. So,cnt
becomes 2. - After third shift to "
1001
",cnt
would remain the same since the first '1' at the fourth position still matches, and the last '1' doesn't change the pattern.
- After second shift to "
-
At every step, we keep checking and updating the minimum flips needed, which in our example remains 2.
The final answer is 2 flips required to make the string alternating, which is the minimum number of flips found during the simulation.
Solution Implementation
1class Solution:
2 def minFlips(self, s: str) -> int:
3 # Determine the length of the input string "s"
4 n = len(s)
5
6 # This string will be used to check against the input string "s"
7 target = "01"
8
9 # Count the number of flips required to match the "01" pattern starting with "0"
10 initial_flips = sum(char != target[i % 2] for i, char in enumerate(s))
11
12 # Initialize the minimum flips answer with the minimum between
13 # matching "01" or "10" pattern starting with "0"
14 min_flips = min(initial_flips, n - initial_flips)
15
16 # Loop over the string "s" to consider all cyclic permutations of "s"
17 for i in range(n):
18 # On each iteration, consider that the first character has moved to the end
19 # Adjust the flip count accordingly
20 initial_flips -= s[i] != target[i % 2]
21 initial_flips += s[i] != target[(i + n) % 2]
22
23 # Update the minimum flips answer considering the current cyclic permutation
24 min_flips = min(min_flips, initial_flips, n - initial_flips)
25
26 # Return the minimum flips answer found
27 return min_flips
28
1class Solution {
2
3 // Method to find the minimum number of flips needed to make the string alternating.
4 public int minFlips(String s) {
5 // Length of the input string
6 int stringLength = s.length();
7
8 // String to represent the pattern "01" which we want to alternate in the final string
9 String alternatingPattern = "01";
10
11 // Count the number of mismatches between the input string and the pattern
12 int mismatches = 0;
13 for (int i = 0; i < stringLength; ++i) {
14 if (s.charAt(i) != alternatingPattern.charAt(i % 2)) {
15 ++mismatches;
16 }
17 }
18
19 // Calculate the minimal flips needed as the minimum between mismatches
20 // and the complement to the length of the string (because we can flip either "0"s or "1"s)
21 int minFlips = Math.min(mismatches, stringLength - mismatches);
22
23 // This for loop mimics the idea of a circular array by going once more through the string,
24 // and adjusting mismatch count as if the string was rotated.
25 for (int i = 0; i < stringLength; ++i) {
26 // If the current character does not match the alternating pattern,
27 // we remove one from mismatches assuming that character is moved to the back
28 if (s.charAt(i) != alternatingPattern.charAt(i % 2)) {
29 --mismatches;
30 }
31
32 // As the character "moves" to the end of the string, we need to check it against
33 // the complementing pattern index.
34 if (s.charAt(i) != alternatingPattern.charAt((i + stringLength) % 2)) {
35 ++mismatches;
36 }
37
38 // Re-calculate the minimum flips after each rotation.
39 minFlips = Math.min(minFlips, Math.min(mismatches, stringLength - mismatches));
40 }
41
42 // After going through all possible rotations, return the minimum flips found.
43 return minFlips;
44 }
45}
46
1class Solution {
2public:
3 int minFlips(string s) {
4 int length = s.size(); // Get the size of the input string
5 string target = "01"; // Define the target pattern
6 int flips = 0; // Initialize the count of flips needed to transform the current string
7
8 // Count how many flips are needed to match the string with the alternating "01" pattern
9 for (int i = 0; i < length; ++i) {
10 if (s[i] != target[i % 2]) { // Check each character against the target pattern
11 ++flips;
12 }
13 }
14
15 // Initialize the answer with the minimum of flips and its inverse
16 // since the string can start with either '0' or '1'
17 int minFlips = std::min(flips, length - flips);
18
19 // Loop through the string considering that the string is circular for optimization
20 for (int i = 0; i < length; ++i) {
21 // If we remove a character that needs flipping from the start, decrease the flip count
22 if (s[i] != target[i % 2]) {
23 --flips;
24 }
25 // If we pretend the removed character is added to the end, and it needs flipping,
26 // increase the flip count
27 if (s[i] != target[(i + length) % 2]) {
28 ++flips;
29 }
30 // Update the answer with the fewest flips required considering the circular rotation
31 minFlips = std::min({minFlips, flips, length - flips});
32 }
33
34 // Return the minimum number of flips to make the string alternating
35 return minFlips;
36 }
37};
38
1function minFlips(s: string): number {
2 const lengthOfString: number = s.length;
3 const alternatingPattern: string = '01'; // The desired pattern is an alternating sequence of '0' and '1'
4 let flipCount: number = 0; // This will count the number of flips to convert the string to the desired pattern
5
6 // Initial pass to count the number of flips needed if we consider the string as is
7 for (let index = 0; index < lengthOfString; ++index) {
8 if (s[index] !== alternatingPattern[index % 2]) { // '%' operator is used to alternate between '0' and '1'
9 ++flipCount;
10 }
11 }
12
13 // The number of flips should be the minimum between flipCount and the count in the opposite sequence
14 let minimumFlips: number = Math.min(flipCount, lengthOfString - flipCount);
15
16 // This loop considers the string as if it were circular, thus we repeat the initial process after virtually 'rotating' the string
17 for (let index = 0; index < lengthOfString; ++index) {
18 // Decrease the flip count when current character is the same as its position in the alternating pattern
19 if (s[index] !== alternatingPattern[index % 2]) {
20 --flipCount;
21 }
22 // Increase the flip count if the character matches the opposite pattern when considered in a circular rotation
23 if (s[index] !== alternatingPattern[(index + lengthOfString) % 2]) {
24 ++flipCount;
25 }
26
27 // Update the minimum flips considering the current rotation
28 minimumFlips = Math.min(minimumFlips, flipCount, lengthOfString - flipCount);
29 }
30
31 return minimumFlips; // Return the minimum number of flips after considering all rotations
32}
33
Time and Space Complexity
The time complexity of the provided code is O(n)
. This is because there is a single loop traversing the string of length n
. Inside the loop, only constant-time operations are performed, such as updating the cnt
variable and comparing values. There are no nested loops or recursive calls that would increase the complexity.
The space complexity of the provided code is O(1)
. The solution is using only a fixed number of variables (n
, cnt
, ans
, target
, and a couple of iterators in the loop) which does not grow with the size of the input. No additional data structures that scale with the input size are used.
Learn more about how to find time and space complexity quickly using problem constraints.
Which algorithm is best for finding the shortest distance between two points in an unweighted graph?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
https algomonster s3 us east 2 amazonaws com cover_photos stack svg Sliding Window Maximum Monotonic Stack We have an array and a sliding window defined by a start index and an end index The sliding window moves from left of the array to right There are always k elements in
Want a Structured Path to Master System Design Too? Don’t Miss This!