[Daily Coding Problem 331] Minimum Flips to make XY string
You are given a string consisting of the letters x
and y
, such as xyxxxyxyy
. In addition, you have an operation called flip
, which changes a single x
to y
or vice versa.
Determine how many times you would need to apply this operation to ensure that all x
's come before all y
's. In the preceding example, it suffices to flip the second and sixth characters, so you should return 2
.
Solution 1. O(N) dynamic programming
dp[i][j]: the minimum flips needed to properly order the substring up to index i, where the final element ends up taking value j.
public class MinimumFlipToMakeXYString { public static int minFlips(String s) { int n = s.length(); int[][] dp = new int[n][2]; dp[0][0] = (s.charAt(0) == 'x' ? 0 : 1); dp[0][1] = (s.charAt(0) == 'y' ? 0 : 1); for(int i = 1; i < n; i++) { dp[i][0] = dp[i - 1][0] + (s.charAt(i) == 'x' ? 0 : 1); dp[i][1] = Math.min(dp[i - 1][0], dp[i - 1][1]) + (s.charAt(i) == 'x' ? 1 : 0); } return Math.min(dp[n - 1][0], dp[n - 1][1]); } public static void main(String[] args) { String s1 = "yyx"; String s2 = "xyxxxyxyyy"; String s3 = "xyxxxyxyyx"; String s4 = "xyxxxyxyyxxx"; String s5 = "yyxxx"; System.out.println(minFlips(s5)); } }
Solution 2. O(N) Prefix Sum
An alternative solution is as follows. First, we make a pass over our input to determine the number of y
's to the left of each element. We then make a second pass to find the number of x
's to the right of each element.
For any solution, there must be some element in our string for which everything to its left gets set to x
, and everything to its right gets set to y
. As a result, we can simply find the pairwise sum of these lists, and use the element which requires the smallest total number of flips.
public class MinimumFlipToMakeXYString { public static int minFlips(String s) { int n = s.length(); int[] leftY = new int[n], rightX = new int[n]; leftY[0] = 0; rightX[n - 1] = 0; for(int i = 1; i < n; i++) { leftY[i] = leftY[i - 1] + (s.charAt(i - 1) == 'y' ? 1 : 0); } for(int i = n - 2; i >= 0; i--) { rightX[i] = rightX[i + 1] + (s.charAt(i + 1) == 'x' ? 1 : 0); } int res = n; for(int i = 0; i < n; i++) { res = Math.min(res, leftY[i] + rightX[i]); } return res; } }