小红的01连续段(二分或者dp)
链接:https://ac.nowcoder.com/acm/contest/69695/B
来源:牛客网
小红定义一个01串的“连续段”为:连续相同字符的极大长度。例如:"110001111"有一个长度为2的连续段,有一个长度为3的连续段,有一个长度为4的连续段。
小红拿到了一个01串,但其中有一些字符不可见了(用'?'表示)。小红想知道,这个01串的连续段长度的最大值最多能达到多少?
输入描述:
一个仅由'0'、'1'、'?'组成的字符串,长度不超过200000。
输出描述:
一个正整数,代表连续段长度的最大长度。
示例1
输入
1?0?1?
输出
3
说明
该字符串可以是"100011",最大的连续段长度为3。
二分
这个答案可以用二分+前缀和解决。sum[i]表示前i个1的个数,然后g[i]表示前i个?的个数,然后我们对答案进行二分,假设二分的答案是x,我们只需要看看全部的长度为x的区间中1的个数+?的个数,或者0的个数+?的个数是否等于区间x
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e6+100;
char a[maxn];
int sum[maxn];
int g[maxn];
int len;
int judge(int x){
for(int i=1,j=x;j<=len;i++,j++){
int x1=sum[j]-sum[i-1];
int x2=g[j]-g[i-1];
int x0=x-x1-x2;
if(x1+x2==x||x2+x0==x){
return 1;
}
}
return 0;
}
int main(){
scanf("%s",a+1);
len=strlen(a+1);
for(int i=1;i<=len;i++){
if(a[i]=='?') g[i]=g[i-1]+1;
else g[i]=g[i-1];
}
//将?看成0
for(int i=1;i<=len;i++){
if(a[i]=='1') sum[i]=sum[i-1]+1;
else sum[i]=sum[i-1];
}
int l=1,r=len,ans;
while(r>=l){
int mid=(l+r)/2;
if(judge(mid)){
l=mid+1;
ans=mid;
}
else{
r=mid-1;
}
}
cout<<ans<<endl;
}
动态规划
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e6+100;
char a[maxn];
int dp[maxn][2];
int ans=0;
int main(){
scanf("%s",a+1);
int len=strlen(a+1);
for(int i=1;i<=len;i++){
if(a[i]=='?'){
dp[i][0]=dp[i-1][0]+1;
dp[i][1]=dp[i-1][1]+1;
}
else{
dp[i][a[i]-'0']=dp[i-1][a[i]-'0']+1;
}
ans=max(ans,max(dp[i][0],dp[i][1]));
}
cout<<ans<<endl;
}