后缀数组 POJ 2217 Secretary

题目链接

题意:求两个字符串的最长公共子串

分析:做法是构造新的串是两个串连接而成,中间用没有出现的字符隔开(因为这样才能保证S的后缀的公共前缀不会跨出一个原有串的范围),即newS = S + '$' + T。对其求sa数组和height数组,取最小值的height[i],且两个后缀串属于不同的字符串。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>

typedef long long ll;
const int N = 1e4 + 5;
std::string t, str;
int sa[N<<1], rank[N<<1];
int height[N<<1];
int tmp[N<<1];

int n, k;
bool cmp_sa(int i, int j) {
    if (rank[i] != rank[j]) {
        return rank[i] < rank[j];
    } else {
        int ri = i + k <= n ? rank[i+k] : -1;
        int rj = j + k <= n ? rank[j+k] : -1;
        return ri < rj;
    }
}

void get_sa(std::string S, int *sa) {
    n = S.length ();
    for (int i=0; i<=n; ++i) {
        sa[i] = i;
        rank[i] = i < n ? (int) S[i] : -1;
    }
    for (k=1; k<=n; k<<=1) {
        std::sort (sa, sa+n+1, cmp_sa);
        tmp[sa[0]] = 0;
        for (int i=1; i<=n; ++i) {
            tmp[sa[i]] = tmp[sa[i-1]] + (cmp_sa (sa[i-1], sa[i]) ? 1 : 0);
        }
        for (int i=0; i<=n; ++i) {
            rank[i] = tmp[i];
        }
    }
}

void get_height(std::string S, int *sa, int *height) {
    int n = S.length ();
    for (int i=0; i<n; ++i) {
        rank[sa[i]] = i;
    }
    int h = 0;
    height[0] = 0;
    for (int i=0; i<n; ++i) {
        int j = sa[rank[i]-1];
        if (h > 0) {
            h--;
        }
        for (; j+h<n && i+h<n; h++) {
            if (S[j+h] != S[i+h]) {
                break;
            }
        }
        height[rank[i]-1] = h;
    }
}

int run(int len1, std::string S) {
    get_sa (S, sa);
    get_height (S, sa, height);
    int ret = 0;
    for (int i=0; i<S.length (); ++i) {
        if ((sa[i]<len1) != (sa[i+1]<len1)) {
            ret = std::max (ret, height[i]);
        }
    }
    return ret;
}

int main() {
    int T; scanf ("%d", &T);
    getchar ();
    while (T--) {
        getline (std::cin, t);
        str = t;
        int len1 = t.length ();
        getline (std::cin, t);
        str += '$' + t;
        int ans = run (len1, str);
        printf ("Nejdelsi spolecny retezec ma delku %d.
", ans);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/Running-Time/p/5448819.html