题目描述
给定只含01的字符串,找出最长平衡子串的长度(平衡串:包含0和1的个数相同),串长最大10^6
输入
一个字符串,只包含01,长度不超过1000000
输出
一行一个整数,最长的0与1的个数相等的子串的长度。
2018北邮的压轴题,想了蛮久的,个人认为主要的点在于,我们可以将0换成-1,然后求前缀和数组dp
,这样当
d
p
[
i
]
=
=
d
p
[
j
]
dp[i]==dp[j]
dp[i]==dp[j]的时候,
d
p
[
i
+
1
]
−
d
p
[
j
]
dp[i+1]-dp[j]
dp[i+1]−dp[j]这个区域内肯定是一个平衡子串,那么问题就变成了求
d
p
[
i
]
=
=
d
p
[
j
]
dp[i]==dp[j]
dp[i]==dp[j]时
j
−
i
j-i
j−i的最大值。我们只需要用一个map,记录所有
d
p
[
k
]
dp[k]
dp[k]首次出现的位置,再找到一个
d
p
[
i
]
=
=
d
p
[
k
]
∣
i
>
k
dp[i]==dp[k]|i>k
dp[i]==dp[k]∣i>k时,二者维护的最长平衡字串长度为
i
−
k
i-k
i−k。
int main() {
string s;
int dp[MAX]; dp[0] = 0;
while (cin>>s)
{
s = ' ' + s;
map<int, int> m;
m[0] = 0;
for (int i = 1; i < s.size(); i++) {
if (s[i] == '0')dp[i] = dp[i - 1] - 1;
else dp[i] = dp[i - 1] + 1;
if (m.find(dp[i]) == m.end())
m[dp[i]] = i;//记录最早出现的这些值的位置
}
int res = 0;
for (int i = 1; i < s.size(); i++) {
int l = m[dp[i]];
if (i - l > res)res = i - l;
}
cout << res << endl;
}
}