持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
如果一个二进制字符串,是以一些 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。
动态规划
单调递增的字符串满足以下性质:
- 首个字符是 0 或 1;
- 其余的每个字符,字符 0 前面的相邻字符一定是 0,字符 1 前面的相邻字符可以是 0 或 1。
当 i>0 时,如果字符串 s 的长度为 i 的前缀即 单调递增,且 和 也满足上述单调递增的顺序,则长度为 的前缀 也单调递增。因此可以使用动态规划计算使字符串 s 单调递增的最小翻转次数。
由于字符串 s 的每个位置的字符可以是 0 或 1,因此对于每个位置需要分别计算该位置的字符是 0 和该位置的字符是 1 的情况下的最小翻转次数。
假设字符串 s 的长度是 n,对于 ,用 和 分别表示下标 i 处的字符为 0 和 1 的情况下使得 单调递增的最小翻转次数。
当 时,对应长度为 1 的前缀,一定满足单调递增,因此 和 的值取决于字符 。具体而言,),其中 为示性函数,当事件成立时示性函数值为 1,当事件不成立时示性函数值为 0。
当 时,考虑下标 i 处的字符。如果下标 i 处的字符是 0,则只有当下标 i - 1 处的字符是 0 时才符合单调递增;如果下标 i 处的字符是 1,则下标 i - 1 处的字符是 0 或 1 都符合单调递增,此时为了将翻转次数最小化,应分别考虑下标 i - 1 处的字符是 0 和 1 的情况下需要的翻转次数,取两者的最小值。
var minFlipsMonoIncr = function(s) {
const n = s.length;
let dp0 = 0, dp1 = 0;
for (let i = 0; i < n; i++) {
const c = s[i];
let dp0New = dp0, dp1New = Math.min(dp0, dp1);
if (c === '1') {
dp0New++;
} else {
dp1New++;
}
dp0 = dp0New;
dp1 = dp1New;
}
return Math.min(dp0, dp1);
};