【经典面试题:最长01子串】 有一个仅由0和1组成的01串,找到其中最长的一段子串,使得该子串中0和1的数目相等

题目

有一个仅由0和1组成的01串,找到其中最长的一段子串,使得该子串中0和1的数目相等

解题思路

  • 如果将0看做-1,则我们要找的子串是最长的和为0的子串。

  • 这种子串求和的问题,一般采用前缀和的方法来解决。

  • 用Sum[i]代表前i个数的和,问题的模型转换为,找到i和j,满足Sum[i] 与Sum[j]相等,且|i-j|最大。

  • 使用Hash表作为辅助数据结构,Hash表中记录了获得某个Sum时最小的i。从左到右遍历Sum[i],在Hash表中查找是否存在,如果存在,则记录下Hash[Sum[i]] 和i的距离差,否则Hash[Sum[i]] = i。一次遍历结束后得到最大的距离差,同时也可以得到具体是哪一段。

代码实现(C++)

#include<bits/stdc++.h>
#define endl '\n';
#define mst(a,b) memset(a,b,sizeof(a));
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int n,m,t;
int dp[maxn];
int main(){
    string str;
    while(cin>>str){
        int zeroIndex = 0;
        int len = str.length();
        dp[1] = (str[0]-'0') == 1? 1:-1;  //将0转变成-1
        for(int i=2;i<=len;i++){
            dp[i] = (str[i-1]-'0') == 1? 1:-1; //将0转变成-1
            dp[i]+=dp[i-1];   //求前缀和
            if(dp[i]==0) zeroIndex=i;  //记录当前前缀和为0的下标位置
        }
        int start = 0 ,maxnlen = 0;
        map<int,int> mp;
        for(int i=1;i<=len;i++){
            if(!mp.count(dp[i])){  //记录首次出现的前缀和的位置
                mp[dp[i]]=i;
            }else{
                start = mp[dp[i]];  //如果有相同的前缀和,求出最长长度
                maxnlen = i-start;
            }
        }
        string ans;
        if(zeroIndex>=maxnlen){  //对于前缀和为0的情况特殊考虑
            maxnlen = zeroIndex;   //与相同前缀和的长度取最大值
            ans = str.substr(0,maxnlen);
        }
        else
            ans = str.substr(start,maxnlen);
        cout<<ans<<" "<<maxnlen<<endl;
    }
    return 0;
}

如果需要详细的步骤介绍,可以参考如下博文:

推荐阅读——SunnyYoona :[经典面试题]最长01子串

学如逆水行舟,不进则退
一百个Chocolate CSDN认证博客专家 CSDN博客专家 Vue爱好者 博客之星
不是只会写业务代码的前端开发攻城狮!博客网站:yangchaoyi.vip做限量版的自己,就这样安静地努力。一个还在苦学前端的小小Chocolate,我的博客主要分享前端、算法、大学课程笔记、平常遇到的bug、心得感悟体会,感谢您的访问,若喜欢可以关注一下~每一个清晨,记得鼓励自己。没有奇迹,只有你努力的轨迹;没有运气,只有你坚持的勇气!每一份坚持都是成功的累积,只要相信自己,总会遇到惊喜!座右铭:学如逆水行舟,不进则退!
©️2020 CSDN 皮肤主题: 程序猿惹谁了 设计师: 上身试试 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值