現在、基本的な文字列の問題、既存のソリューションKMP、次の配列の問題、ハッシュ、マナチャー、ブルートフォースマッチング、ルーラーと辞書ツリー、接尾辞配列、acオートマトン、接尾辞オートマトンの場合、
kmp
部分文字列は親文字列にあります。文字列マッチングの問題を解決するための出現回数
char a[maxn],b[maxn];
ll lena,lenb;
int next1[maxn];
void getnext(){
next1[0]=-1;
int i=0,j=-1;
while(i<lena){
//子串
if(j==-1||a[i]==a[j]){
//子串
i++;j++;
if(a[i]==a[j]) next1[i]=next1[j];
else next1[i]=j;
}
else{
j=next1[j];
}
}
}
int KMP(){
int i=0,j=0,ans=0;
while(i<lena&&j<lenb){
//子串 母串
if(i==-1||a[i]==b[j]){
i++;j++;
}
else i=next1[i];
if(i==lena){
ans++;//出现次数....
i=next1[i];
}
}
return ans;
}
次の配列を個別に探す:リングタイプが繰り返し発生する問題と、定義に関するいくつかの判断を解決します
int next1[maxn];
void getnext()
{
next1[0]=-1;
int i=0,j=-1;
while(i<lena)
{
if(j==-1||a[i]==a[j])
{
i++;j++;
if(a[i]==a[j])next1[i]=next1[j];
else next1[i]=j;
}
else
{
j=next1[j];
}
}
}
ハッシュ:数値を使用して文字列を格納し、他の文字列で数値を判断します。これは主に、文字列照合の問題を解決する方法です。
ll hash1[maxn];
int lena,lenb;
for(int i=0;i<lena;i++){
sum=sum*base+(int)a[i];
}//子串的哈希值
hash1[0]=0;
for(int i=1;i<=lenb;i++){
hash1[i]=hash1[i-1]*base+b[i-1];
}//每个位置上从前向后的哈希值
馬車:弦の回文の長さの問題を解決する
string Manacher(string s1){
string s="$#";//占空位0插入符号1
for(int i=0;i<s1.size();i++)
s+=s1[i],s+='#';
vector<int>p(s.size(),0);//p储存回文串长度
int id=0,mx=0,maxpoint=0,maxlen=0;//mx对应最右边 id为对应中点 maxpoint最长回文对应中点 maxlen最长长度
for(int i=1;i<s.size();i++){
p[i]=mx>i+p[i]?min(mx-i,p[2*id-i]):1;
while(s[i+p[i]]==s[i-p[i]]) ++p[i];
if(i+p[i]>mx) id=i,mx=i+p[i];//更新右端和中间,节间更新左边端点
if(p[i]>maxlen) maxlen=p[i],maxpoint=i;//更新最大长度和对应中心点
}
return s1.substr((maxpoint-maxlen)/2,maxlen-1);//s1中最长回文串
}
暴力的な一致:つまり、親文字列上の各文字の位置を判断するには、一致する場合は次の文字が一致するかどうかを判断し、一致しない場合は次の位置にジャンプします
最近、ac automataの内容について少し学びましたが、ボードの後ろに補足の質問をするときに詳しく書きますが、これはascallコードで書かれた質問であることを忘れないでください。
int trie[maxn][4], fail[maxn], tail[maxn];
int n, m, pos;
char s[15];
map<char, int>idx;
void insert(){
int ls=strlen(s),root=0;
for(int i=0;i<ls;i++){
int x=idx[s[i]];
if(trie[root][x]==0)
trie[root][x]=++pos;
root=trie[root][x];
}
tail[root]=1;
}
void getfail(){
queue<int>qu;
for(int i=0;i<4;i++){
if(trie[0][i]){
fail[trie[0][i]]=0;
qu.push(trie[0][i]);
}
}
while(!qu.empty()){
int now=qu.front();
qu.pop();
for(int i=0;i<4;i++){
if(trie[now][i]){
fail[trie[now][i]]=trie[fail[now]][i];
qu.push(trie[now][i]);
}
else trie[now][i]=trie[fail[now]][i];
tail[trie[now][i]]|=tail[trie[fail[now]][i]];
}
}
}
最長の回文文字列
一般的に、最長の回文は馬車を使用し、2次元のdpで転送することもできます。文字列の場合、dp [i] [j]を使用して、文字列のi番目の文字からj文字までの最長の回文サブシーケンスを表します。s
[i] == s [j]の場合、転送できます。回文サブシーケンスの両側で、s [i]!= s [j]が両側に転送できない場合、すべてのdp [i] [j] = d [i + 1] [j-1] +2
同時にパリンドロームのサブシーケンス、したがってdp [i] [j] = max(d [i + 1] [j]、dp [i] [j-1])
最長の回文を形成する2つの弦の違いについては、
#include<bits/stdc++.h>
using namespace std;
char a[55],b[55];
int f[55][55][55][55];
int main(){
int t;
cin>>t;
while(t--){
scanf("%s",a+1);
scanf("%s",b+1);
int m,n;
n=strlen(a+1);
m=strlen(b+1);
int ans=0;
for(int len1=0;len1<=n;len1++)
for(int len2=0;len2<=m;len2++)
for(int i=1;i+len1-1<=n;i++)
for(int j=1;j+len2-1<=m;j++){
int r=i+len1-1;
int l=j+len2-1;
if(len1+len2<=1) f[i][r][j][l]=1;
else{
f[i][r][j][l]=0;
if(len1>1) f[i][r][j][l]|=((f[i+1][r-1][j][l])&&(a[i]==a[r]));
if(len1&&len2) f[i][r][j][l]|=(f[i+1][r][j][l-1]&&(a[i]==b[l]));
if(len1&&len2) f[i][r][j][l]|=(f[i][r-1][j+1][l]&&(a[r]==b[j]));
if(len2>1) f[i][r][j][l]|=(f[i][r][j+1][l-1]&&(b[j]==b[l]));
}
if(f[i][r][j][l]){
ans=max(ans,len1+len2);
}
}
cout<<ans<<endl;
}
system("pause");
return 0;
}