样例输入:
9
0 1 0 0 0 1 1 0 0
样例输出:
6
思想
我刚开始是这样写的,从两端枚举i,j,这样可以尽快找到满足条件的最大长度段。
每枚举两个端点,我都用前缀和求一下两个端点内的区间和,看一下区间和是否等于总长度的一半(如果该区间1半是1,一半是0,那区间和刚好为长度的一半)。
如果是满足条件的区间,我就存一下该区间的长度。最后在所有合法区间长度中取一个最大长度即是答案。
复杂度方面i,j从左右两端枚举,时间复杂度为O(n),前缀和求区间和复杂度为O(1),总共时间复杂度为O(n)。
但是实际上这样算复杂度是错误的,因为i,j并不是O(n)复杂度,而是O(n^2)。
双指针要求i,j都只遍历一次,总共遍历到n,但是上面的代码针对每个i,j都会全部遍历。
#include<bits/stdc++.h>
using namespace std;
int n ;
const int N=1e5+10;
int a[N],sum[N];
int maxn=-0x3f3f3f3f;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
for(int i=1;i<=n;i++)
{
for(int j=n;j>=1;j--)
{
int Sum=sum[j]-sum[i];
int Sub=j-i;
double t=Sub*1.0/2;
if((double)Sum==t)
{
maxn=max(maxn,j-i);
}
}
}
cout<<maxn;
return 0;
}
正解
看一下官方题解视频再看一下评论区这位老哥的代码就明白了。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int n;
int cnt, maxlength;
int main()
{
cin >> n;
for (int i = 0; i < n; i++)cin >> a[i];
unordered_map<int, int> count_mp;
count_mp[0] = -1;
for (int i = 0; i < n; i++)
{
cnt += a[i] ? 1 : -1;
if (count_mp.find(cnt)!=count_mp.end())
{
int previdx = count_mp[cnt];
int length = i - previdx;
maxlength = max(maxlength, length);
}
else
{
count_mp[cnt] = i;
}
}
cout << maxlength;
return 0;
}
什么意思呢?就是说我设男为1,女为-1。
假设我前一段区间的和是5,经过一段区间之后的和还是5,说明中间这段区间肯定男女个数相同,给消掉了。
那我就求一下这段区间的长度,最后所有这种情况的长度求一个最大值即可。