思路:贪心+前缀和 利用预处理计算出以字符串S[i]为中断点时,往前0比1多的最大长度以及往后1比0多的最大长度,这样遍历S即可得到最长子串长度。
求S[i]时往前时0比1多的最大长度 Len,可先求前缀和,将‘1’作为1,‘0’作为-1处理, 当前缀和 l[i]=k,要0比1多,当 k<0时len=i+1, 当 k>=0时 则需要找到最早满足l[i]-l[j]<0即 l[j]=k+1时的最小下标,因此只要先保存预先保存 l[j]=k+1的最小下标即第一次出现时的下标即可,同理同样处理后缀和
Code :
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int MAX_N=1000005;
int n;
string str;
int l[MAX_N],r[MAX_N];
vector<int> vl,vr;
int main()
{
ios::sync_with_stdio(false);
cin>>str;
n=str.size();
int sum=0,t=1;
for(int i=0;i<n;++i)
{
if(str[i]=='1') ++sum;
else --sum;
l[i]=sum;
if(sum==t){ //只需要记录sum为1-n时第一次出现的下标
vl.push_back(i);
++t;
}
}
sum=0,t=1;
for(int i=n-1;i>=0;--i)
{
if(str[i]=='0') ++sum;
else --sum;
r[i]=sum;
if(sum==t){
vr.push_back(i);
++t;
}
}
int nl=vl.size(),nr=vr.size(),ans=0;
for(int i=0;i<n-1;++i)
{
int sl=-1,sr=-1;
if(l[i]<0) sl=i+1;
else if(nl>l[i]) sl=i-vl[l[i]];
if(r[i+1]<0) sr=n-i-1;
else if(nr>r[i+1]) sr=vr[r[i+1]]-i-1;
if(sl!=-1&&sr!=-1) ans=max(ans,sl+sr);
}
cout<<ans<<endl;
return 0;
}