题目:
一个只有0,1组成的字符串,每一次操作可以把一个字符从0到1或者从1到0,求最少操作次数形成单调不减字符串
思路:
一开始用DP,果断超时。。。。。一直以为1s可以跑1e9,结果只能跑1e8
因为只有两种形式的字符,到最后肯定后面部分是1,前面部分是0,当然可以全0全1的情况。那么我们只需要找到这个分界点,使得包括分界点左边全是0,右边全是1.怎么找分界点呢?我们可以统计前面部分1的个数,和从后往前统计0的个数,然后遍历每一个点,计算这个点左边1的个数和右边0的个数,这就是我们需要操作的次数,因为我们需要把左边的1全变为0,右边的0全变为1.找其中的最小值就行了。统计0,1个数和遍历分界点为线性时间复杂度。
代码:
class Solution {
public:
int minFlipsMonoIncr(string S) {
int len = S.length();
if(len==0)return 0;
int one[20000+50]; //统计从0到i点的1的个数
int zero[20000+50];//统计i到结尾的0的个数
memset(one,0,sizeof(one));
memset(zero,0,sizeof(zero));
if(S[0]=='1')one[0] = 1;
else one[0] = 0;
for(int i=1;i<len;i++){
if(S[i]=='1')one[i] = one[i-1] + 1;
else one[i] = one[i-1];
}
if(S[len-1]=='0')zero[len-1] =1;
else zero[len-1] = 0;
for(int i=len-1;i>=0;i--){
if(S[i]=='0'){
zero[i] = zero[i+1] +1;
}
else zero[i] = zero[i+1];
}
int ma = zero[0];
zero[len] = 0;
for(int i=0;i<len;i++){ //遍历分界点
ma = min(ma,one[i]+zero[i+1]);
}
// for(int i=0;i<len;i++)cout<<dp[i]<<" ";cout<<endl;
// cout<<len<<endl;
return ma;
}
};