一、 题目描述
如果一个由 ‘0’ 和 ‘1’ 组成的字符串,是以一些 ‘0’(可能没有 ‘0’)后面跟着一些 ‘1’(也可能没有 ‘1’)的形式组成的,那么该字符串是 单调递增 的。
我们给出一个由字符 ‘0’ 和 ‘1’ 组成的字符串 s,我们可以将任何 ‘0’ 翻转为 ‘1’ 或者将 ‘1’ 翻转为 ‘0’。
返回使 s 单调递增 的最小翻转次数。
输入:s = “00110”
输出:1
解释:我们翻转最后一位得到 00111.
输入:s = “010110”
输出:2
解释:我们翻转得到 011111,或者是 000111。
输入:s = “00011000”
输出:2
解释:我们翻转得到 00000000。
二、代码思路
代码思路参考:
建议好好复习一下动态规划的题目,动态规划问题是我认为目前刷题以来遇到的一种比较不好解决的问题,简单题是很有规律的,你可以很轻松找到状态转换方程并解决。但是,针对一般题目就不是那么容易做了,状态的拆解、状态之间的转换不是很容易能看出来的。
所以,往往是这题思路没有,看完题解恍然大悟,再看一题还是不会,哈哈哈哈哈。只能多练,多学习别人的思路,多总结前人的做题方法,最后形成自己的东西。
三、代码题解
class Solution {
public int minFlipsMonoIncr(String s) {
//这种题经典没思路
//但是,又是涉及到这种局部有很多状态,每个局部状态都会影响最终结果的问题,往往是动态规划。
//通过分析题目,我找到一个思路:
//1、遇到1之后该翻转成0还是说将后面的全反转成1。
//2、所以,我们可以抽象出状态转换方程:dp1就是将1不变后面全转成1,dp2就是将1变成0,接着判断。不会做
//https://leetcode.cn/problems/cyJERH/solution/dong-tai-gui-hua-jiang-wei-yi-bu-bu-you-ojinj/
//dp[i] = Math.min(length0, )
int n = s.length();
int[] zero = new int[n];
int[] one = new int[n];
zero[0] = s.charAt(0) == '0' ? 0 : 1;
one[0] =s.charAt(0) == '0' ? 1 : 0;
for (int i = 1; i < n; i++) {
if (s.charAt(i) == '0') {
//该字符为0 前置必须是0
zero[i] = zero[i - 1];
//该字符转成1, 前置转成1可以,前置转成0也可以;
one[i] = Math.min(one[i - 1] + 1, zero[i - 1] + 1);
} else {
one[i] = Math.min(one[i - 1], zero[i - 1]);
zero[i] = zero[i - 1] + 1;
}
}
return Math.min(one[s.length() - 1], zero[s.length() - 1]);
}
}
时间复杂度降低一些:
class Solution {
public int minFlipsMonoIncr(String s) {
//这种题经典没思路
//但是,又是涉及到这种局部有很多状态,每个局部状态都会影响最终结果的问题,往往是动态规划。
//通过分析题目,我找到一个思路:
//1、遇到1之后该翻转成0还是说将后面的全反转成1。
//2、所以,我们可以抽象出状态转换方程:dp1就是将1不变后面全转成1,dp2就是将1变成0,接着判断。不会做
//https://leetcode.cn/problems/cyJERH/solution/dong-tai-gui-hua-jiang-wei-yi-bu-bu-you-ojinj/
//dp[i] = Math.min(length0, )
int n = s.length();
int zero = 0;
int one = 0;
zero = s.charAt(0) == '0' ? 0 : 1;
one =s.charAt(0) == '0' ? 1 : 0;
for (int i = 1; i < n; i++) {
if (s.charAt(i) == '0') {
//该字符为0 前置必须是0
//该字符转成1, 前置转成1可以,前置转成0也可以;
one = Math.min(one + 1, zero + 1);
zero = zero;
} else {
one = Math.min(one, zero);
zero = zero + 1;
}
}
return Math.min(one, zero);
}
}