Solution For Flip String To Monotone Increasing
Problem Statement:
A string of ‘0’s and ‘1’s is given. We need to flip the minimum number of ‘0’s to ‘1’s such that the resulting string is monotone increasing.
Monotone increasing string means that every character to the right of the current character should be greater than or equal to the current character.
Input: “00110”
Output: 1
Explanation: We need to flip the 1st zero to ‘1’, resulting in “10110”, which is monotone increasing.
Solution Approach:
Let’s start by understanding the problem statement. We need to convert a string to monotone increasing by flipping the minimum number of ‘0’s to ‘1’s. We can achieve this by iterating the string from left to right and keeping track of the number of ‘0’s encountered so far. For each ‘1’ encountered, we check how many ‘0’s are encountered before it. If the number of ‘0’s is less than the current minimum, we update the minimum. We also keep track of the number of ‘1’s encountered so far. After iterating through the string, we get the total number of ‘0’s and ‘1’s in the string. There are two cases:
- If the number of ‘0’s is 0, then the string is already monotone increasing, and we return 0.
- If the number of ‘0’s is greater than 0, then we need to flip the minimum number of ‘0’s to ‘1’s such that the resulting string is monotone increasing. We can achieve this by flipping all the ‘0’s to the left of the minimum ‘0’ we encountered during iteration. Thus, the number of ‘0’s flipped will be the minimum of the total number of ‘0’s and the number of ‘1’s encountered before the minimum ‘0’ during iteration.
Let’s implement the above approach in code:
public int minFlipsMonoIncr(String S) {
int len = S.length();
int[] zeros = new int[len];
int[] ones = new int[len];
int countZeros = 0, countOnes = 0;
for(int i=0; i<len; i++) {
zeros[i] = countZeros;
ones[i] = countOnes;
if(S.charAt(i) == ‘0’) {
countZeros++;
} else {
countOnes++;
}
}
int minFlips = Integer.MAX_VALUE;
for(int i=0; i<len; i++) {
int flips = zeros[i] + ones[len-1] – ones[i];
minFlips = Math.min(minFlips, flips);
}
return minFlips;
}
First, we initialize two arrays ‘zeros’ and ‘ones’ of length ‘len’. We also initialize two counters to keep track of the number of ‘0’s and ‘1’s encountered so far. We iterate through the string, updating the ‘zeros’ and ‘ones’ arrays with the count of ‘0’s and ‘1’s encountered so far. Next, we iterate through the ‘zeros’ array and for each element, we calculate the total number of ‘0’s that need to be flipped to the right of the current element and the total number of ‘1’s encountered up to the current element. We add these two values to get the total number of ‘0’s that need to be flipped to make the string monotone increasing. Finally, we return the minimum number of flips required.
Time Complexity: O(N), where N is the length of the input string.
Space Complexity: O(N), where N is the length of the input string.
Step by Step Implementation For Flip String To Monotone Increasing
/** * This problem can be solved using a greedy approach. We can keep track of the number of flips required * to make the string monotone increasing from the left and from the right. At each step, we will take * the minimum of the two values and add it to the total number of flips required. * * For example, consider the string "00110". * To make this string monotone increasing from the left, we would need to flip the first and second characters. * To make it monotone increasing from the right, we would need to flip the second and third characters. * Therefore, the minimum number of flips required is 2. */ public class Solution { public int minFlipsMonoIncr(String S) { int N = S.length(); int[] P = new int[N+1]; for (int i = 0; i < N; ++i) P[i+1] = P[i] + (S.charAt(i) == '1' ? 1 : 0); int ans = Integer.MAX_VALUE; for (int j = 0; j <= N; ++j) { ans = Math.min(ans, P[j] + N-j-(P[N]-P[j])); } return ans; } }
def minFlipsMonoIncr(self, S): # Write your code here # we can use a greedy algorithm to solve this problem # we will keep track of the number of flips needed to make the string all 0's # and all 1's # we will compare these numbers and return the smaller one # we will also keep track of the number of 1's and 0's seen so far # as we iterate through the string # if we see a 1, we increment the number of 1's seen # if we see a 0, we increment the number of 0's seen # and we compare the number of 1's seen to the number of 0's seen # whichever is smaller is the number of flips needed for that character # we add this number of flips to our total # we can also keep track of the number of flips needed to make the string all 1's # by iterating through the string in reverse # this will give us the total number of flips needed for the string # whichever of these two totals is smaller is the answer # initialize variables one_flips = 0 zero_flips = 0 total_flips = 0 # iterate through string for i in range(len(S)): # if character is a 1 if S[i] == '1': # increment number of 1's seen one_flips += 1 # compare number of 1's seen to number of 0's seen # whichever is smaller is the number of flips needed for that character # add this number of flips to our total total_flips += min(one_flips, zero_flips) # if character is a 0 else: # increment number of 0's seen zero_flips += 1 # compare number of 1's seen to number of 0's seen # whichever is smaller is the number of flips needed for that character # add this number of flips to our total total_flips += min(one_flips, zero_flips) # iterate through string in reverse for i in range(len(S)-1, -1, -1): # if character is a 1 if S[i] == '1': # increment number of 1's seen one_flips += 1 # compare number of 1's seen to number of 0's seen # whichever is smaller is the number of flips needed for that character # add this number of flips to our total total_flips += min(one_flips, zero_flips) # if character is a 0 else: # increment number of 0's seen zero_flips += 1 # compare number of 1's seen to number of 0's seen # whichever is smaller is the number of flips needed for that character # add this number of flips to our total total_flips += min(one_flips, zero_flips) # return the smaller of the two totals return min(total_flips, one_flips)
var flipMonotoneIncreasing = function(S) { // This problem can be solved by greedily flipping the most valuable character at each step. // The value of a character is the number of characters that would need to be flipped // to make the string monotone increasing if that character was flipped. // For example, the string "0100110" has the following values: // '0': 4 (flipping this would result in the string "1100110") // '1': 3 (flipping this would result in the string "0010110") // '0': 2 (flipping this would result in the string "0110110") // '1': 1 (flipping this would result in the string "0100101") // '1': 0 (flipping this would result in the string "0100110") // '0': 0 (flipping this would result in the string "0100110") // The most valuable character to flip at each step is the one with the largest value. // We can keep track of the values of each character using two arrays: // one for the number of 0's that need to be flipped to make the string monotone increasing, // and one for the number of 1's that need to be flipped to make the string monotone increasing. // For example, the string "0100110" would be represented by the arrays: // [4, 3, 2, 1, 0, 0] // [3, 2, 1, 0, 0, 0] // We can fill in these arrays using a single pass through the string. // For each character, we update the values of the next character based on the current character. // If the current character is a '0', then we know that the next character will need to be flipped // if it is a '1'. Thus, we increment the value of the next character in the "1" array. // Similarly, if the current character is a '1', then we know that the next character will need to be flipped // if it is a '0'. Thus, we increment the value of the next character in the "0" array. // After we have filled in the arrays, we can find the most valuable character to flip at each step // by taking the maximum of the two arrays at each index. // For example, in the array [4, 3, 2, 1, 0, 0], the most valuable character to flip at each step is: // 4 (flipping '0' at index 0) // 3 (flipping '1' at index 1) // 2 (flipping '0' at index 2) // 1 (flipping '1' at index 3) // 0 (flipping '0' at index 4) // 0 (flipping '0' at index 5) // We can keep track of the number of flips we have made by summing up the values in the array. // In this example, the final sum would be 4 + 3 + 2 + 1 + 0 + 0 = 10, // which is the minimum number of flips required to make the string monotone increasing. const n = S.length; // Create two arrays, one for the number of 0's that need to be flipped and one for the number of 1's. const flip0 = Array(n).fill(0); const flip1 = Array(n).fill(0); // Fill in the arrays using a single pass through the string. for (let i = 0; i < n - 1; i++) { const c = S.charAt(i); // If the current character is a '0', then we know that the next character will need to be flipped // if it is a '1'. Thus, we increment the value of the next character in the "1" array. if (c === '0') { flip1[i + 1] = flip1[i] + 1; } // Similarly, if the current character is a '1', then we know that the next character will need to be flipped // if it is a '0'. Thus, we increment the value of the next character in the "0" array. else { flip0[i + 1] = flip0[i] + 1; } } // Find the most valuable character to flip at each step by taking the maximum of the two arrays. let flips = 0; for (let i = 0; i < n; i++) { flips += Math.max(flip0[i], flip1[i]); } return flips; };
class Solution { public: int minFlipsMonoIncr(string S) { //DP solution int n = S.length(); //Create a dp array of size n+1 //dp[i][0] represents the minimum flips required to make the first i characters of S all '0's //dp[i][1] represents the minimum flips required to make the first i characters of S all '1's int dp[n+1][2]; //Fill in base cases dp[0][0] = 0; //No flips required to make the first 0 characters all '0's dp[0][1] = 0; //No flips required to make the first 0 characters all '1's for(int i = 1; i <= n; i++){ //If the ith character is '0' if(S[i-1] == '0'){ //The number of flips required to make the first i characters all '0's is the same as the number required to make the first i-1 characters all '0's dp[i][0] = dp[i-1][0]; //The number of flips required to make the first i characters all '1's is 1 + the number required to make the first i-1 characters all '0's dp[i][1] = 1 + dp[i-1][0]; } //If the ith character is '1' else{ //The number of flips required to make the first i characters all '0's is 1 + the number required to make the first i-1 characters all '1's dp[i][0] = 1 + dp[i-1][1]; //The number of flips required to make the first i characters all '1's is the same as the number required to make the first i-1 characters all '1's dp[i][1] = dp[i-1][1]; } } //The minimum number of flips required is the minimum of dp[n][0] and dp[n][1] return min(dp[n][0], dp[n][1]); } };
public int MinFlipsMonoIncr(string S) { int N = S.Length, ans = N; // This is the upper bound (flipping all bits). // For example, with S = "00110": // ans = min(ans, 1 + flip("00110")) // ans = min(ans, 1 + flip("00011")) // ans = min(ans, 2 + flip("00110")) // ans = min(ans, 2 + flip("00011")) // ans = min(ans, 2 + flip("00001")) // ans = min(ans, 3 + flip("00110")) // ans = min(ans, 3 + flip("00011")) // ans = min(ans, 3 + flip("00001")) // ans = min(ans, 3 + flip("00000")) int[,] P = new int[N, 2]; // P[i,j] = number of ones needed to have j ones at the end of the string S[i..N-1] for (int j = 0; j <= 1; ++j) { int p = 0; // accumulates the number of ones needed to have j ones at the end of the string S[0..i-1] for (int i = 0; i < N; ++i) { P[i, j] = p; if (S[i] == '1') { p++; } } } for (int i = 0; i < N; ++i) { for (int j = 0; j <= 1; ++j) { ans = Math.Min(ans, P[i, j] + (1 - j) + (N - 1 - i) - P[N - 1, 1 - j]); } } return ans; }