题目描述:
解答:
第一眼看到这个题目,只想到了将0转为-1(貌似曾经见过一次这种类型、印象比较深),然后想前缀和,但是对于X的这个位置,想了很久,看了眼复杂度,应该是 O (n) 的方法。
正文:维护一个leftlen[i] : 以i为结尾,0比1多的长度。 rightlen[i]:同理;pos[n] : 数n第一次出现的位置。
遍历数组,if(sum[i]<0) leftlen[i] = i; else leftlen[i] = i - pos[sum[i]+1]; (这里,为什么是sun[i]+1呢? 因为我们需要一个数字,来满足0比1多的条件(使得sum[i]-sum[l-1]<0),那么这个数字就应该比sum[i]大,而这是个01串,所以最早出现的一定是(sum[i]+1)这个值。)
附上鄙人AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000100;
int pos[maxn];
int leftlen[maxn];
int rightlen[maxn];
int sum[maxn];
int a[maxn];
int ans = 0;
int main()
{
string s;
cin>>s;
int n = s.size();
for(int i = 0;i<n;i++)
{
if(s[i]=='0')
a[i+1] = -1;
else a[i+1] = 1;
}
for(int i = 1;i<=n;i++)
{
sum[i] = sum[i-1]+a[i];
if(sum[i]<0)
leftlen[i] = i;
else
{
if(pos[sum[i]+1])
{
leftlen[i] = i - pos[sum[i]+1];
}
else
{
leftlen[i] = 0;
pos[sum[i]] = i;
}
}
}
memset(pos,0,sizeof(pos));
memset(sum,0,sizeof(sum));
for(int i = n;i>0;i--)
{
sum[i] = sum[i+1]+a[i];
if(sum[i]>0)
{
rightlen[i] = n-i+1;
}
else
{
if(pos[-(sum[i]-1)])
{
rightlen[i] = pos[-(sum[i]-1)] - i;
}
else
{
rightlen[i] = 0;
pos[-(sum[i])] = i;
}
}
}
for(int i = 1;i<=n;i++)
{
if(leftlen[i]>0&&rightlen[i+1]>0)
ans = max(rightlen[i+1]+leftlen[i],ans);
}
printf("%d",ans);
return 0;
}