文字列の基本的なアルゴリズム

トライ

Trieは、ルートが空のノードinitであるツリーであり、ルートから各ノードへのパスは単語の接頭辞を構成します
これは、4つの単語{abcd、abcde、abce、bcd}で構成される辞書ツリーであり、非常に直感的です。黄色のノードは、この文字が単語の終わりであることを示します)。
このツリーで単語を見つけるには、ルートから開始して単語の終わりまで少しずつ一致させ、位置がマークされているかどうかを確認するだけです(黄色)。
ここに画像の説明を挿入します(ディクショナリツリーの目的は、主に、多くのソース文字と共通のプレフィックスを持つ文字列作成することです。クエリ中に、ターゲットソースディクショナリ存在するかどうかをすばやく判断できます

一般に、辞書ツリーノードには2つのサブ属性visとnumがあります。vis [t-'a ']配列は彼の息子tの位置を表します。vis[t-'a'] = 0の場合、tの息子がいないことを意味します。numは現在で終わる単語の数を表します。ノード。

struct 
{
    
    
    ll vis[26];
    ll num;
}trie[maxn];

辞書ツリーの一般的な機能は、挿入と検索です。

ll tot=0;
void insert(string s)插入一个单词
{
    
    
    int now=0;
    for(auto x:s)按位遍历字典树
    {
    
    
    	now表示当前位置(初始值为0就是init结点),x表示下一个字母
        if(trie[now].vis[x-'a'])now=trie[now].vis[x-'a'];如果树上有这个字母就往下走
        else如果树上没有这个字母
        {
    
    
            trie[now].vis[x-'a']=++tot;就在末尾建立一个结点,将vis指针指向这个节点
            now=trie[now].vis[x-'a'];
            初始化这个节点
            rep(i,0,25)trie[now].vis[i]=0;
            trie[now].num=0;
        }
    }
    当退出循环的时候now位于这个单词末尾
    trie[now].num++;将以该字母结尾的单词个数+1
}
看懂了插入的话查找就是小意思了。
ll find(string s)
{
    
    
    int now=0;
    for(auto x:s)
    {
    
    
        if(trie[now].vis[x-'a'])now=trie[now].vis[x-'a'];
        else return 0;
    }
    return trie[now].num;
}

要約すると、辞書ツリーを学びました。

km²

推奨されるブログの
次の配列の本質は次のとおりです。最長の共通プレフィックスサフィックス。文字列が一致しない場合、最長の共通プレフィックスの1桁後に一致し始めます。

char a[maxn];
ll kmp[maxn];
scanf("%s",a+1);
ll lena=strlen(a+1),j=0;
rep(i,2,lena)
{
    
    
    while(j>0&&a[j+1]!=a[i])j=kmp[j];
    if(a[j+1]==a[i])j++;
    kmp[i]=j;
}

エイホ-コラシックオートマトン

推奨されるブログ
acautomataは、長い文字列に複数の短い文字列が表示される回数をカウントできます。
このプロセスでは、最初にn個の短い文字列を使用してトライを作成し、次に長い文字列を使用してトライをビット単位で照合します。不一致が発生した後、ツリーの特定の位置にジャンプします(不一致のプレフィックスの最長の接尾辞はトライで見つかりました)アルゴリズムのマッチングを続行します。
コアは、失敗配列であるジャンプ位置を前処理することです。
素晴らしいことは、失敗はdp
trie [trie [u]。Vis[i]]で計算できることです。Fail= trie [trie [u]。Fail]。Vis[i] trie [trie [u] .vis [i ]]。fail = trie [trie [u] .fail] .vis [i]t r i e [ t r i e [ u ] v i s [ i ] ] f a i l=T R I E [ T R I E [ U ] F I L ] V I S [ I ]
そうO(M)O(M)O m 失敗失敗を処理しましたf a i l

void getfail()
{
    
    
    queue<ll>q;
    rep(i,0,25)
    {
    
    
        if(trie[0].vis[i]!=0)
        {
    
    
            trie[trie[0].vis[i]].fail=0;
            q.push(trie[0].vis[i]);
        }
    }
    while(!q.empty())
    {
    
    
        ll p=q.front();
        q.pop();
        rep(i,0,25)
        {
    
    
            ll to=trie[p].vis[i],fail=trie[p].fail;
            if(to==0)trie[p].vis[i]=trie[fail].vis[i];
            else
            {
    
    
                trie[to].fail=trie[fail].vis[i];
                q.push(to);
            }
        }
    }
}

Loguacオートマトンボードの問題

牛の姉妹テストで
は、n個の単語が与えられ、各単語は重みvalを持ち、長さLの文字列を作成し、最大優先度値を見つけます。これも重みを計算するときの関係を含みます。つまり、abcの値は2、abの値は1、文字列abcを作成する値は2 + 1 = 3です。

トライでは、dp、dp [i] [j]は、長さがiで、位置がj〜で終わる文字列の最大値を表します。

マナチャー

for(int i=1;i<=2*len;i++)
{
    
    
    if(mx>i)p[i]=min(p[2*id-i],mx-i);
    else p[i]=0;
    while(s[i+p[i]+1]==s[i-p[i]-1])++p[i];
    if(id+p[i]>mx)
    {
    
    
        mx=id+p[i];
        id=i;
    }
}

おすすめ

転載: blog.csdn.net/solemntee/article/details/113208317