持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情
一、题目
LeetCode 将字符串翻转到单调递增
如果一个二进制字符串,是以一些 0(可能没有 0)后面跟着一些 1(也可能没有 1)的形式组成的,那么该字符串是 单调递增 的。
给你一个二进制字符串 s,你可以将任何 0 翻转为 1 或者将 1 翻转为 0 。
返回使 s 单调递增的最小翻转次数。
示例 1:
输入:s = "00110"
输出:1
解释:翻转最后一位得到 00111.
示例 2:
输入:s = "010110"
输出:2
解释:翻转得到 011111,或者是 000111。
示例 3:
输入:s = "00011000"
输出:2
解释:翻转得到 00000000。
提示:
1 <= s.length <= 105
s[i] 为 '0' 或 '1'
二、题解
要符合单调递增的字符串,那么字符0前的字符就只能为0,而字符1前的字符可以为0或者为1。
方法一
字符串的每一个字符只会是0或者1,那么可以通过动态规划来搞得这个。定义一个同等大小的数组dp0,那么dp0[i]就表示字符串s的下标i的字符为0时下标i前的字符为单调递增的最小翻转次数;定义一个同等大小的数组dp1,那么dp1[i]就表示字符串s的下标i的字符为1时下标i前的字符为单调递增的最小翻转次数。初始的对于字符串s的第一个字符来说,不管其是0还是1都属于单调递增的,所以对于dp0[0]应为0,同样的dp1[0]也为0。然后遍历字符串s的其余字符c,当字符c为0的时候,只有i - 1处的字符为0才符合单调递增,所以dp0[i] = dp0[i - 1];当字符c为1的时候,i - 1处的字符不管是0还是1都符合单调递增的,所以应该取两者最小的翻转次数,所以dp1[i] = min(dp0[i - 1], dp1[i - 1])。当遍历字符串结束之后,dp0和dp1中哪一个小就是哪一个获取的值为最小的翻转次数。对于动态规划使用的数组可以发现遍历过程中只使用了前一个状态值,所以为了优化空间可以使用两个变量代替两个数组。
三、代码
方法一 Java代码
class Solution {
public int minFlipsMonoIncr(String s) {
int dp0 = 0;
int dp1 = 0;
for (int i = 0; i < s.length(); i++) {
dp1 = Math.min(dp0, dp1);
if (s.charAt(i) == '1') {
dp0 += 1;
} else {
dp1 += 1;
}
}
return Math.min(dp0, dp1);
}
}
时间复杂度:O(n),需要遍历一次字符串,判断每个字符的状态。
空间复杂度:O(1),只需使用常数的空间。