String · 28 of 43
Number of flips to make binary string alternate
Count the fewest 0 and 1 flips that make a row of digits take turns, like 0101 or 1010.
- Simple way
- time O(n)
room O(n) - Clever way
- time O(n)
room O(1)
The problem, simply
You get a string of 0 and 1. One flip turns a single 0 into 1 or a 1 into 0. Find the fewest flips so that no two neighbors are the same.
There are only two strings like that for any length: one that starts with 0 (0101...) and one that starts with 1 (1010...). The answer is the cheaper of the two.
A story to remember it
Picture it
s = 0001010111 under the two goals. Goal A disagrees in 2 places, goal B in the other 8.
- rejected
Examples
A normal case
- In
s = '0001010111'- Out
2
Flip index 1 and index 8 to get 0101010101.
Short string
- In
s = '001'- Out
1
Flip the first digit to get 101.
All the same
- In
s = '1111'- Out
2
Both goals, 0101 and 1010, need 2 flips.
Already alternating
- In
s = '010'- Out
0
Nothing to fix.
Tiny
- In
s = '0'- Out
0
One digit has no neighbors, so it always alternates.
Way 1: the simple way
Write out both goal strings in full. Then compare s with each one, letter by letter, and count how many places differ.
- Build goal A:
0at even places,1at odd places. - Build goal B: the opposite.
- Count where
sdiffers from each goal. Return the smaller count.
class Solution {
public int minFlips(String s) {
int n = s.length();
StringBuilder a = new StringBuilder(), b = new StringBuilder();
for (int i = 0; i < n; i++) {
a.append(i % 2 == 0 ? '0' : '1'); // 0101...
b.append(i % 2 == 0 ? '1' : '0'); // 1010...
}
int flipsA = 0, flipsB = 0;
for (int i = 0; i < n; i++) {
if (s.charAt(i) != a.charAt(i)) flipsA++;
if (s.charAt(i) != b.charAt(i)) flipsB++;
}
return Math.min(flipsA, flipsB);
}
}How long it takes: a few walks over the string, O(n). Extra room: two goal strings as long as s, O(n).
Way 2: the clever way
You do not need to write the goals down. Goal A wants i % 2 at place i: 0 at even places and 1 at odd places. And every place that agrees with goal A disagrees with goal B. So count only the flips for A, and B costs n - flipsA.
- For each place
i, the digit iss[i] - '0'and goal A wantsi % 2. - If they differ, add one to
flipsA. - Return
min(flipsA, n - flipsA).
Counting flips for 0001010111
01 / 08
Goal A starts with 0 and takes turns: 0101010101. We count how many letters of s disagree with it. Goal B (1010101010) is the exact opposite, so we do not need to count it.
- flips for A
- 0
- looking now
- done
- answer
- rejected
class Solution {
public int minFlips(String s) {
int n = s.length();
int flipsA = 0; // flips to reach 0101...
for (int i = 0; i < n; i++) {
int digit = s.charAt(i) - '0';
if (digit != i % 2) flipsA++; // goal A wants i % 2 here
}
return Math.min(flipsA, n - flipsA); // goal B is the opposite
}
}How long it takes: one walk, O(n). Extra room: one counter, O(1).
Watch out for
- Compare the digit with the number
i % 2, not the character.'0'is 48, not 0, so convert with- '0'. - The empty string and a single digit need 0 flips. The formula gives 0 for both.
- If the string can hold other characters, check them first.
What interviewers ask next
- Swaps instead of flips (LeetCode 1864)? Swaps cannot change how many 0s and 1s there are. Pick a goal whose counts match, then the answer is half the number of places that disagree with it.
- You may also move the first digit to the end, any number of times (LeetCode 1888)? Glue
s + sand slide a window of lengthn, keeping the mismatch count for both goals as the window moves. StillO(n). - Return the fixed string, not just the count? Build the cheaper goal.
- Same idea on a grid, like a chessboard? A cell
(r, c)wants(r + c) % 2. Count mismatches and take the smaller of the count and its opposite.
Remember this
Grown-up words: the tiles are bits, repainting is a bit flip, the two floors are the two alternating target patterns, and n - flipsA uses the fact that the patterns are complements of each other.