題目描述
給定一個0-1串,請找到一個儘可能長的連續子串,其中包含的0與1的個數相等。
組數很多,注意常數優化。。。
輸入
一個字符串,只包含01,長度不超過1000000
輸出
一行一個整數,最長的0與1的個數相等的子串的長度。
思路:如果某子串中0與1的個數相等那麼該子串的代數和肯定等於0。如果最長子串是從開頭開始的那麼
當代數和等於0出現的最後邊的位置即最長子串的末尾,該子串即最長子串;如果不是從開頭開始的,那
麼最長子串即代數和相等的兩個位置的距離最長的那個子串。用一個數組dis[]來記錄加和首次出現的位
置,如果該加和還沒有出現過就記錄下來此時位置,由於是從前往後遍歷的,則首次記錄的位置肯定是最
前邊的位置,那麼同等加和出現的位置越往後則兩者距離就越長。詳細請看代碼即代碼旁的註釋。
示例輸入
1011 1111 1010
示例輸出
2 0 4
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
char num[2000000]; //存儲01數字串
int dis[2000002]; //記錄代數和首次出現的位置
int main()
{
//freopen("lalala.text","r",stdin);
while(~scanf("%s",num))
{
memset(dis,-1,sizeof(dis)); //初始化爲-1
int len=strlen(num);
int sum=0,mm=0; //sum記錄從開頭到當前位置的代數和,mm代表此時最長子串的長度
for(int i=0; i<len; i++)
{
if(num[i]=='1') //如果是1就+1
sum++;
else if(num[i]=='0') //如果是0就-1
sum--;
if(sum==0) //如果代數和是0就說明該最長子串是從頭開始的
{
mm=max(mm,i+1); //只要出現0就比一下最長長度
continue;
}
if(dis[sum+1000000]==-1) //爲了以防出現負數sum+1000000保證下標始終爲正;如果此時的代數和之前沒出現過則記錄下來此時的位置
dis[sum+1000000]=i;
else //如果此代數和之前出現過就計算一下當前位置距離首次此代數和出現位置有多遠,然後再與mm比較取最大
{
mm=max(mm,i-dis[sum+1000000]);
}
}
printf("%d\n",mm);
}
return 0;
}