Crazy Binary String
题意:给你一个长度为n的01字符串,问该字符串中01个数相等的最长子串和子序列分别是多少。
分析:
首先,大家要知道什么是子序列,什么是子串,子序列是不一定是连续的,它可以是原串中任意元素按照相对位置组成的序列,但是子串就不是了,子串一定是连续的,不可分割的按照绝对位置组成的序列。
知道这个概念之后,大家可以明显的看出,子序列这个答案好求,就是暴力一下,看看这个字符串中0,1的个数,谁最小,最后的答案就是这个最小值乘2;
那子串怎么求,这是个难点。仔细观察可以发现,这与01的对数是有一定的关系的,那么不妨就从这个方面入手,我们定义一个int变量dis,如果当前的字符是0,那么dis–,否则dis++,如果这个dis是第一次出现,那么就用一个数组存一下出现当前这个dis 的下标,如果说这个dis不是第一次出现,那么就用当前这个字符的下标减去下标为dis这个数组里面的值。这就是答案。
为什么呢,因为dis定义为出现0,就减一,出现1就加一,那么当其值不是第一次出现的时候,那么肯定就用当前这个下标减去第一次出现这个值的位置了;
这是因为0与1相互抵消才会产生的现象,只有他们出现的次数相等,才会出现抵消的情况。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<string>
#include<cmath>
#include<cstring>
#include<set>
#include<queue>
#include<stack>
#include<map>
typedef long long ll;
using namespace std;
const int N=1e5+100;
char str[N];
map<int ,int >ma;
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif // ONLINE_JUDGE
int n;
scanf("%d%s",&n,str+1);
int dis=0;
int num_0=0,num_1=0;
for(int i=1;i<=n;i++){
if(str[i]=='0')
num_0++;
else
num_1++;
}
int ans=0;
ma[0]=0;
for(int i=1;i<=n;i++){
if(str[i]=='0') dis--;
else dis++;
if(ma.count(dis)==0)//这个地方一定要注意,不能用!ma[dis],这样是过不了这组数据:2 01
ma[dis]=i;
else
ans=max(ans,i-ma[dis]) ;
}
printf("%d %d\n",ans,min(num_0,num_1)*2);
return 0;
}