问题:
给定01组成的字符串,求反转(0->1 or 1->0)最少次数,使得成为0...001..11(0..00 or 1..11)这样的单调增字符串。求反转次数。
Example 1: Input: "00110" Output: 1 Explanation: We flip the last digit to get 00111. Example 2: Input: "010110" Output: 2 Explanation: We flip to get 011111, or alternatively 000111. Example 3: Input: "00011000" Output: 2 Explanation: We flip to get 00000000. Note: 1 <= S.length <= 20000 S only consists of '0' and '1' characters.
解法:
DP动态规划:
dp[i]到第i个字符的最少反转次数。->coutflip
cout1[i]出现1的次数=1->0的次数
状态转移方程:
选择:S[i]作为最后一个字符被加进来的时候,
if S[i]=1 then
选择不反转:(现在是后半段)coutflip[i-1]。
选择反转(1->0):(现在是前半段)cout[i](还没做过选择,因此为可表示的固定值)
求两者中的最小:coutflip[i]=min(coutflip[i-1], cout[i])
if S[i]=0 then
选择反转(0->1):(现在是后半段)coutflip[i-1]+1(上次的结果+本次反转)
选择不反转:(现在是前半段)cout1[i-1] (所有1的反转次数)(还没做过选择,因此为可表示的固定值)
求两种选择下的最小值:coutflip[i]=min(coutflip[i-1]+1, cout1[i-1])
⚠️注意:
前半段的时候,cout1[i]>=coutflip[i]
后半段的时候,由于不只反转1,还变化的反转了0,因此二者大小不确定了。
代码参考:
1 class Solution { 2 public: 3 int minFlipsMonoIncr(string S) { 4 int coutflip=0, cout1=0; 5 for(char a:S){ 6 if(a=='1') cout1++; 7 else coutflip++; 8 coutflip=min(coutflip, cout1); 9 } 10 return coutflip; 11 } 12 };