• 《后缀数组》


    1:后缀排序。

    基于倍增和桶排的做法。

    对于每个位置有第一关键字和第二关键字。

    利用倍增来求解关键字,当所有人的排名都不一样时即完成。

    2:LCP

    最长公共前缀,非常有用。

    洛谷:

    P3809 【模板】后缀排序

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 1e6 + 5;
    const int M = 1e3 + 5;
    const LL Mod = 1000000;
    #define pi acos(-1)
    #define INF 1e12
    #define dbg(ax) cout << "now this num is " << ax << endl;
    namespace FASTIO{
        inline LL read(){
            LL x = 0,f = 1;char c = getchar();
            while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
            while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
            return x*f;
        }
    }
    using namespace FASTIO;
    
    char s[N];
    int x[N],y[N],c[N],sa[N],rk[N],height[N],n,m;
    //x - 第一关键字,y - 第二关键字,c - 桶,sa - 排名为i的后缀编号的首位下标,rk - 编号为i的后缀的排名,height[i] = LCP(i,i - 1),LCP - 最长公共前缀
    void SA() {
        for(int i = 1;i <= n;++i) x[i] = s[i],c[x[i]]++;//桶统计
        for(int i = 2;i <= m;++i) c[i] += c[i - 1];//前缀和
        for(int i = n;i >= 1;--i) sa[c[x[i]]--] = i;
        for(int k = 1;k <= n;k = (k << 1)) {//倍增
            int num = 0;
            for(int i = n - k + 1;i <= n;++i) y[++num] = i;//后k位不存在
            for(int i = 1;i <= n;++i) {
                if(sa[i] > k) {
                    y[++num] = sa[i] - k;//可做其他的第二关键字
                }
            }
            for(int i = 1;i <= m;++i) c[i] = 0;
            for(int i = 1;i <= n;++i) c[x[i]]++;
            for(int i = 2;i <= m;++i) c[i] += c[i - 1];
            for(int i = n;i >= 1;--i) sa[c[x[y[i]]]--] = y[i],y[i] = 0;//更新sa
            swap(x,y);
            num = 1,x[sa[1]] = 1;
            for(int i = 2;i <= n;++i) {//更新x数组
                if(y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) x[sa[i]] = num;
                else x[sa[i]] = ++num;
            }
            if(num == n) break;//满足所有排名都不一样退出。
            m = num;
        }
        for(int i = 1;i <= n;++i) printf("%d%c",sa[i],i == n ? '
    ' : ' ');
    }
    void LCP() {
        int k = 0;
        for(int i = 1;i <= n;++i) rk[sa[i]] = i;//初始化rk
        for(int i = 1;i <= n;++i) {
            if(rk[i] == 1) {
                height[1] = 0;
                continue;
            }
            if(k) k--;//更新k
            int j = sa[rk[i] - 1];
            while(i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++;
            height[rk[i]] = k;
        }
        for(int i = 1;i <= n;++i) printf("%d%c",height[i],i == n ? '
    ' : ' ');
    }
    int LCP(int x,int y){//LCP(x,y) = min(height[k]) (x < k <= y)
        int ans = INF;
        for(int i = x + 1;i <= y;++i) {
            ans = min(ans,height[i]);
        }
        return ans;
    }
    int main()
    {
        scanf("%s",s + 1);
        n = strlen(s + 1);
        m = 122;
        SA();
        system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    C#图片处理示例(裁剪,缩放,清晰度,水印)
    lucene4.5近实时搜索
    mongo 多条件 查询
    Lucene:QueryParser
    Lucene的中文分词器IKAnalyzer
    Lucene为不同字段指定不同分词器(转)
    Thrift初用小结
    lucene4.0与之前版本的一些改变
    lucene 资料
    Mongodb快速入门之使用Java操作Mongodb
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/14403435.html
Copyright © 2020-2023  润新知