B. Balanced Substring (DP + 前缀和 + map)

本文介绍了一种利用前缀和思想及动态规划方法,解决在0、1字符串中寻找最长平衡子串的问题。通过将0转换为-1,利用dp数组记录累积和,结合map或数组记录首次出现的累积和位置,从而高效地找到最长平衡子串的长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

B. Balanced Substring

You are given a string s consisting only of characters 0 and 1. A substring [l, r] of s is a string slsl + 1sl + 2… sr, and its length equals to r - l + 1. A substring is called balanced if the number of zeroes (0) equals to the number of ones in this substring.

You have to determine the length of the longest balanced substring of s.

Input
The first line contains n (1 ≤ n ≤ 100000) — the number of characters in s.

The second line contains a string s consisting of exactly n characters. Only characters 0 and 1 can appear in s.

Output
If there is no non-empty balanced substring in s, print 0. Otherwise, print the length of the longest balanced substring.

Examples

input
8
11010111
output
4
input
3
111
output
0
Note
In the first example you can choose the substring [3, 6]. It is balanced, and its length is 4. Choosing the substring [2, 5] is also possible.

In the second example it’s impossible to find a non-empty balanced substring.

题意:

给你一个0,1构成的字符串,让你在该字符串中找出最长的平衡子串。

题目分析:

题目意思很简单,但是要实现却需要些技巧。看到这题,首先想到用dp去解决,但是后来发现,前i项之间并没有明显的规律可循,于是想到动态规划中的前缀和思想,为了将dp数组的下标与其内容连起来,我们把s串中的 0 当成 -1 处理。

则我们可以得到:

if ( s [ i - 1 ] == 0) dp [ i ] = dp [ i - 1 ] - 1;
if ( s [ i - 1 ] == 1) dp [ i ] = dp [ i - 1 ] + 1;

那么接下来就简单了,我们只要记录出开始的位置,那么字串区间长度就可以等于 i 减去初始位置。这里我们要注意,因为我们的 0 用了 -1 来处理,所以我们的范围则变成了 - 1e6 ~ 1e6 ,我可以选择使用数组来记录初始位置,我们也可以使用map。

先来说,如果使用数组vis [ ] 的话,我们需要将数组开大一倍,并且设置一个数 MAX = 1e6 来处理数组中出现的负数,即 vis [ dp [ i ] + MAX ] ;
而我们如果用map来进行记录的话,可以直接定义一个map,而不需要浪费如此大的空间去存储,可以大大降低空间复杂度。

代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <map>
#include <stack>
#define maxn 2000005
#define INF 0x3f3f3f
using namespace std;

typedef long long ll;

int n;
char s[maxn];
int dp[maxn];
map<int, int> vis;

int main()
{
    scanf("%d", &n);
    memset(dp, 0, sizeof(dp));
    scanf("%s", s);
    for (int i = 1; i <= n; i++)
    {
        if (s[i - 1] == '0')
            dp[i] = dp[i - 1] - 1;
        if (s[i - 1] == '1')
            dp[i] = dp[i - 1] + 1;
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        if (vis[dp[i]] == 0 && dp[i] != 0)
            vis[dp[i]] = i;
        else
            ans = max(i - vis[dp[i]], ans);
    }
    /*
    for(int i = 0; i <= n; i ++)
        cout << dp[i] << ' ';
    cout << endl;
    for(int i = 0; i <= n; i ++)
        cout << vis[i] << ' ';
    cout << endl; 
    */
    cout << ans << endl;
    //system("pause");
    return 0;
}

/*
 0  1  2  3  4  5  6  7  8
 1  1  0  1  0  1  1  1
 0  1  2  1  2  1  2  3  4
 0  1  2  1  2  1  2  7  8
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值