zoukankan      html  css  js  c++  java
  • poj 2774 Long Long Message 后缀数组LCP理解

    题目链接

    题意:给两个长度不超过1e5的字符串,问两个字符串的连续公共子串最大长度为多少?

    思路:两个字符串连接之后直接后缀数组+LCP,在height中找出max同时满足一左一右即可;

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string.h>
    #include<algorithm>
    #include<map>
    #include<queue>
    #include<vector>
    #include<cmath>
    #include<stdlib.h>
    #include<time.h>
    using namespace std;
    typedef long long ll;
    const int MAXN = 200007;
    char s[MAXN],str[MAXN];
    int sa[MAXN],t[MAXN],t2[MAXN],c[MAXN],n;
    void build_sa(int m,int n) // m为字符ASCII码的最大值+1;n = strlen(s) + 1;
    {
        int i,*x = t, *y = t2;
        for(i = 0;i < m; i++) c[i] = 0;
        for(i = 0;i < n; i++) c[x[i] = s[i]]++;
        for(i = 1;i < m; i++) c[i] += c[i-1];
        for(i = n - 1;i >= 0; i--) sa[--c[x[i]]] = i;
        for(int k = 1;k <= n;k <<= 1){
            int p = 0;
            for(i = n - k;i < n;i++) y[p++] = i;
            for(i = 0;i < n;i++) if(sa[i] >= k) y[p++] = sa[i] - k;
    
            for(i = 0;i < m;i++) c[i] = 0;
            for(i = 0;i < n;i++) c[x[y[i]]]++;
            for(i = 1;i < m;i++) c[i] += c[i-1];
            for(i = n - 1;i >= 0;i--) sa[--c[x[y[i]]]] = y[i];
    
            swap(x,y);
            x[sa[0]] = 0;// 将字符彻底转变为序号;
            for(i = 1,p = 1;i < n;i++)
                x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    }
    int rk[MAXN],height[MAXN];
    void getHeight()
    {
        int i,j,k = 0;
        for(i = 1;i <= n;i++) rk[sa[i]] = i; // rk[i]:后缀i在sa[]中的下标
        for(i = 0;i < n;i++){
            if(k) k--;
            if(rk[i] == 0) continue;
            j = sa[rk[i] - 1];
            while(i+k<n && j+k<n && s[i+k] == s[j+k]) k++;
            height[rk[i]] = k; // h[i] = height[rk[i]]; h[i] >= h[i-1] - 1;
        }
    }
    int main()
    {
        while(scanf("%s%s",s,str) == 2){
            int len = strlen(s);
            s[len] = '#';s[len+1] = '';
            strcat(s,str);
            n = strlen(s);
            s[n] = '#';
            build_sa('z'+1,n+1);
            getHeight();
            int ans = -1;
            for(int i = 2;i <= n;i++)
                if(height[i] > ans && ((sa[i] < len && sa[i-1] > len) || (sa[i] > len && sa[i-1] < len)))
                    ans = height[i];
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Java实现 LeetCode 30 串联所有单词的子串
    Java实现 LeetCode 29 两数相除
    Java实现 LeetCode 29 两数相除
    Java实现 LeetCode 29 两数相除
    Java实现 LeetCode 28 实现strStr()
    Java实现 LeetCode 28 实现strStr()
    Java实现 LeetCode 28 实现strStr()
    Java实现 LeetCode 27 移除元素
    Java实现 LeetCode 27 移除元素
    字符编码终极笔记:ASCII、Unicode、UTF-8、UTF-16、UCS、BOM、Endian
  • 原文地址:https://www.cnblogs.com/hxer/p/5376647.html
Copyright © 2011-2022 走看看