/** * 字符串只包含0和1,将字符串翻转到单调递增 */ public class Test { /** * 两种方法计算的值是一致的 * @param args */ public static void main(String[] args) { String str = "000000110011111000111110"; System.out.println( getMinFlip(str) == minFlipsMonoIncrb(str)); } /** * 这种方法比较直接,将字符串分为两部分,第一部分统计1的个数,第二部分统计0的个数,再相加 * 时间复杂度为O(N^2) * @param S * @return */ public static int minFlipsMonoIncrb(String S) { int result = S.length(); for (int i = 0; i < S.length(); i++) { char[] str1 = S.substring(0, i).toCharArray(); char[] str2 = S.substring(i + 1, S.length()).toCharArray(); int zero = 0; int one = 0; for (int j = 0; j < str1.length; j++) { if (str1[j] == '1') zero++; } for (int j = 0; j < str2.length; j++) { if (str2[j] == '0') one++; } int re = zero + one; if (re < result) result = re; } return result; } /** * 这种方法在计算int[] one 和int[] zero数组时候,利用了前一个下标的值来计算后一个的值 * 时间复杂度为O(N) * @param str * @return */ public static int getMinFlip(String str){ int len = str.length(); int [] one = new int[len]; // [i] = a 从左边开始统计,下标为i时,左边的1的个数为a int[] zero = new int[len]; // [i] = b 从右边开始统计,下标为i时,右边的0的个数为b if(str.charAt(0) == '1'){ one[0] = 1; }else { one[0] = 0; } for (int i = 1; i<len; i++){ if(str.charAt(i) == '1'){ one[i] = one[i-1]+1; }else { one[i] = one[i - 1]; } } if(str.charAt(len-1) == '0'){ zero[len-1] = 1; }else{ zero[len-1] = 0; } for(int j = len-2;j>=0;j--){ if(str.charAt(j) == '0'){ zero[j] = zero[j + 1] + 1; }else{ zero[j] = zero[j+1]; } } //one[len-1] 表示的意思是当把字符串变为全0时,要翻转的步数 //zero[0] 表示的意思是当把字符串变为全1时,要翻转的步数 int min = Integer.min(zero[0], one[len - 1]); for(int k = 0; k < len-1; k++){ int temp = zero[k+1] + one[k] ; //one[k] + zero[k+1] 组成一个分割点 min = Integer.min(temp, min); } return min; } }