题目链接
思路
- 假设f(i)为前i个字符有序的最小翻转数,那么f(i)和f(i-1)的数目关系要分情况讨论,如果f(i-1)以0结尾,那么f(i)可以以0结尾,也可以以1结尾;相反,如果f(i-1)以1结尾,那么f(i)必须以1结尾
- 因此可以假设f(i)为前i个字符有序且以1结尾的最小翻转数、g(i)为前i个字符有序且以0结尾的最小翻转数
- 那么状态转换方程为:
- s[i] = 1 时 g(i)=g(i-1)+1 f(i)=min{f(i-1),g(i-1)}
- s[i] = 0 时 g(i)=g(i-1) f(i)=min{f(i-1),g(i-1)}+1
- 解释一波~ 对于g(i)来说,如果s[i]=0,那么g(i)不用翻转,且因为g(i)表示最终子串以0结尾,所以前一位(第i-1位)只能是0所以g(i)=g(i-1);如果s[i]=1,那么g(i)需要翻转,所以g(i)=g(i-1) + 1
- 对于f(i)来说,如果s[i]=0,那么f(i)必须要翻转,但是此时前i-1位可以以0结尾,也可以以1结尾,所以有f(i)=min{f(i-1),g(i-1)}+1;那么当s[i]=1时,f(i)不需要翻转,所以f(i)=min{f(i-1),g(i-1)}
class Solution {
public int minFlipsMonoIncr(String s) {
int[][] dp = new int[2][2];
dp[0][0] = s.charAt(0) == '0' ? 0 : 1;
dp[0][1] = 1 - dp[0][0];
for (int i = 1; i < s.length(); i++) {
char ch = s.charAt(i);
dp[i % 2][0] = dp[(i - 1) % 2][0] + (ch == '0' ? 0 : 1);
dp[i % 2][1] = Math.min(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1]) + (ch == '1' ? 0 : 1);
}
return Math.min(dp[(s.length() - 1) % 2][0], dp[(s.length() - 1) % 2][1]);
}
}