【线性 dp】B017_LC_将字符串翻转到单调递增(分类讨论)

一、Problem

如果一个由 ‘0’ 和 ‘1’ 组成的字符串,是以一些 ‘0’(可能没有 ‘0’)后面跟着一些 ‘1’(也可能没有 ‘1’)的形式组成的,那么该字符串是单调递增的。

我们给出一个由字符 ‘0’ 和 ‘1’ 组成的字符串 S,我们可以将任何 ‘0’ 翻转为 ‘1’ 或者将 ‘1’ 翻转为 ‘0’。

返回使 S 单调递增的最小翻转次数。

示例 1:
输入:"00110"
输出:1
解释:我们翻转最后一位得到 00111.

示例 2:
输入:"010110"
输出:2
解释:我们翻转得到 011111,或者是 000111。

示例 3:
输入:"00011000"
输出:2
解释:我们翻转得到 00000000。

提示:

1 <= S.length <= 20000
S 中只包含字符 ‘0’ 和 ‘1’

二、Solution

方法一:dp

突破点在弄清楚第 i i i 为字符为 0/1 时翻转策略,就两种吧:翻转/不翻转;两种决策都不会对后面的结果造成干扰,故可用 dp

  • 定义状态
    • f [ i ] f[i] f[i] 表示将前 i i i 个字符变为单调递增的最少翻转次数
  • 思考初始化:
    • f [ 0 ] = 0 f[0] = 0 f[0]=0
  • 思考状态转移方程
    • s [ i ] = 0 s[i] = 0 s[i]=0 时, f [ i ] = m i n ( c 1 , f [ i − 1 ] + 1 ) f[i] = min(c1, f[i-1]+1) f[i]=min(c1,f[i1]+1),不翻转该位置的 0 的话,如果要保持递增只能翻转前面的所有 1 咯;翻转的话,次数加 1
    • s [ i ] = 1 s[i] = 1 s[i]=1 时, f [ i ] = m i n ( f [ i − 1 ] , c 1 + 1 ) f[i] = min(f[i-1], c1+1) f[i]=min(f[i1],c1+1),1 就是我们想要的,所以不用翻转,此时的翻转次数就取决于前面的翻转情况了;翻转的话,只能去翻转前面的以及当前的 1
  • 思考输出 f [ n ] f[n] f[n]
class Solution {
public:
    int minFlipsMonoIncr(string s) {
    	int n = s.size(), c1 = 0;
    	vector<int> f(n+1); f[0] = 0;
        
    	for (int i = 1; i <= n; i++) {
    		if (s[i-1] == '0') f[i] = min(c1, f[i-1] + 1);
    		else 			   f[i] = min(f[i-1], ++c1);
    	}
    	return f[n];
    }
};

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)

你可能感兴趣的:(#,线性,dp)