问题描述
小S有一个二进制字符串
s,他可以将任意0翻转为1,或将1翻转为0,以使字符串变为单调递增的形式。一个字符串是单调递增的,当它是由一些0(可能没有0)跟随一些1(可能没有1)组成的。你的任务是帮助小S计算使字符串单调递增的最小翻转次数。
例如:当
s = "00110"时,最小的翻转次数是1,可以将第二个1翻转为0使字符串变为"00010"。
测试样例
样例1:
输入:
s = "00110"输出:1样例2:
输入:
s = "010110"输出:2样例3:
输入:
s = "00011000"输出:2样例4:
输入:
s = "11100"输出:2
解题思路
-
由于可以
0变1和1变0,我们考虑字符串以0结尾和以1结尾的情况,两种情况取最小变化 -
设表示在第个字符时,以
0结尾的最小变化数量 -
设表示在第时,以
1结尾的最小变化数量 -
如果当前字符
- ,由以
0结尾的次数转换过来 - , 由的最小次数 + 1(当前字符变为1)转换
- ,由以
-
如果当前字符
- ,只能由以
0结尾的次数+1转换过来,因为要求单调递增 - , 得到前面的最小转换次数,当前字符不需要转换
- ,只能由以
-
最后取即可
核心代码
int solution(const string& s) {
int n = s.length();
vector<vector<int>> f(n + 1, vector<int>(2, 0));
for (int i = 1; i <= n; i++) {
if (s[i - 1] == '0') {
f[i][0] = f[i - 1][0];
f[i][1] = min(f[i - 1][0], f[i - 1][1]) + 1;
} else {
f[i][0] = f[i - 1][0] + 1;
f[i][1] = min(f[i - 1][0], f[i - 1][1]);
}
}
return min(f[n][0], f[n][1]);
}
优化
-
可以看出当前只依赖于,我们可以用两个变量来代替
-
表示以
0结尾的最小转换次数, 表示以1结尾的最小转换次数 -
当时,
- 由得到
- 不变
-
当时,
- ,这一步要在后面,因为的变化依赖于
优化代码
int solution(const string& s) {
int n = s.length();
int f0 = 0, f1 = 0;
for(int i=0; i < n; i++) {
f1 = min(f0, f1) + (s[i] == '0');
f0 += s[i] == '1';
}
return min(f0, f1);
}