[各種面接問題]重なる長男串
2925 ワード
重複する長男の列:
タイトルの説明:
2つの文字列を与え、それらが前後に重なる最長子列の長さを求める.例えば、「abcde」と「cdefg」は「cde」であり、長さは3である.
入力:
入力には、複数のテストケースが含まれる場合があります.各テストケースには1行のみで、2つの文字列が含まれています.文字列の長さは1000000を超えず、文字'a'-'z'のみが含まれます.
出力:
各テストケースに対応して,それらが前後に重なる最長子列の長さを出力する.
サンプル入力:
サンプル出力:
第1の反応はやはり接尾辞の配列で、aとbをつなぎ合わせて、接尾辞の配列のhの配列を求めて、それから答えを探す時bソースの列のこの接尾辞を探してそれからaと始まるある接尾辞のhの最小値の中の最大値を探して、このようにすべきです.このステップがhを求めた後に線形時間で求められるかどうか考えてみましょう..
接尾辞の配列は先に置いて、别に考えて、KMPととても似ていると感じて、ある接尾辞とある接頭辞の最大の似ている长さを求めて、実はKMPの第1部で、PREの配列を构筑します.まず、新しい列t=b+aを構築する.これでaの接尾辞とbの接頭辞の最大類似長になる.
注意最後に戻るときはpre[t.length()−1]+1を直接返すことはできず,aの長さを超えるか否かも判断する.
それから問題解を見て、人はKMPを拡張して、思想はKMPと似ていますが、私はもっと最大の回文子列に似ていて、すでに得た範囲を利用して現在の値を更新していると思います.
ここに図がありますが、見ると分かりやすいです.
http://blog.sina.com.cn/s/blog_6974c8b20101054d.html
KMPを拡張する2つのステップは似ています.
それから拡張KMPの問題を貼ります:http://blog.csdn.net/xingyeyongheng/article/details/9386671
タイトルの説明:
2つの文字列を与え、それらが前後に重なる最長子列の長さを求める.例えば、「abcde」と「cdefg」は「cde」であり、長さは3である.
入力:
入力には、複数のテストケースが含まれる場合があります.各テストケースには1行のみで、2つの文字列が含まれています.文字列の長さは1000000を超えず、文字'a'-'z'のみが含まれます.
出力:
各テストケースに対応して,それらが前後に重なる最長子列の長さを出力する.
サンプル入力:
abcde cdefg
サンプル出力:
3
第1の反応はやはり接尾辞の配列で、aとbをつなぎ合わせて、接尾辞の配列のhの配列を求めて、それから答えを探す時bソースの列のこの接尾辞を探してそれからaと始まるある接尾辞のhの最小値の中の最大値を探して、このようにすべきです.このステップがhを求めた後に線形時間で求められるかどうか考えてみましょう..
接尾辞の配列は先に置いて、别に考えて、KMPととても似ていると感じて、ある接尾辞とある接頭辞の最大の似ている长さを求めて、実はKMPの第1部で、PREの配列を构筑します.まず、新しい列t=b+aを構築する.これでaの接尾辞とbの接頭辞の最大類似長になる.
注意最後に戻るときはpre[t.length()−1]+1を直接返すことはできず,aの長さを超えるか否かも判断する.
#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<climits>
#include<algorithm>
using namespace std;
char a[1000005];
char b[1000005];
int longestCover(string& a,string& b)
{
string t(b+a);
vector<int> pre(t.length(),-1);
for(int i=1;i<t.length();i++)
{
int p=pre[i-1];
while(p!=-1&&t[p+1]!=t[i])
p=pre[p];
if(t[p+1]==t[i])
pre[i]=p+1;
}
return min((int)a.length(),pre[t.length()-1]+1);
}
int main()
{
while(scanf("%s%s",a,b)!=EOF)
{
string aa(a),bb(b);
int ans=longestCover(aa,bb);
printf("%d
",ans);
}
}
それから問題解を見て、人はKMPを拡張して、思想はKMPと似ていますが、私はもっと最大の回文子列に似ていて、すでに得た範囲を利用して現在の値を更新していると思います.
ここに図がありますが、見ると分かりやすいです.
http://blog.sina.com.cn/s/blog_6974c8b20101054d.html
KMPを拡張する2つのステップは似ています.
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int getLonestCover(string& s,string& t)
{
vector<int> a(t.length(),0);
a[0]=t.length();
int len=0;
while(1+len<t.length()&&t[len]==t[1+len])
len++;
a[1]=len;
int k=1,mx=k+a[k]-1;
for(int i=2;i<t.length();i++)
{
int w=i-k;
if(i+a[w]-1<mx)
a[i]=a[w];
else
{
int len=max(0,mx-i+1);
while(i+len<t.length()&&t[0+len]==t[i+len])
len++;
a[i]=len;
k=i,mx=i+a[i]-1;
}
}
vector<int> b(s.length(),0);
len=0;
while(len<s.length()&&len<t.length()&&s[len]==t[len])
len++;
b[0]=len;
k=0,mx=len-1;
for(int i=1;i<s.length();i++)
{
int w=i-k;
if(i+a[w]-1<mx)
b[i]=a[w];
else
{
int len=max(0,mx-i+1);
while(i+len<s.length()&&len<t.length()&&s[i+len]==t[len])
len++;
b[i]=len;
k=i,mx=i+b[i]-1;
}
}
int ans=0;
for(int i=0;i<s.length();i++)
if(b[i]==s.length()-i)
{
ans=b[i];
break;
}
return ans;
}
int main()
{
string a,b;
while(cin>>a>>b)
{
int ret=getLonestCover(a,b);
cout<<ret<<endl;
}
}
それから拡張KMPの問題を貼ります:http://blog.csdn.net/xingyeyongheng/article/details/9386671