題目
有一個僅由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子串
學如逆水行舟,不進則退