zoukankan      html  css  js  c++  java
  • Poj 2774 Long Long Message (后缀数组)

    题目链接:

      Poj  2774  Long Long Message

    题目描述:

      给出A,B两个字符串,求最长公共子串?

    解题思路:

      求A,B字符串的最长公共子串可以转化为求A,B字符串后缀数组的最长公共前缀。把B串连接在A串后面,用'$'隔开组成r串。求出r串的height数组,最大的height[i](满足sa[i]与sa[i-1]不在同一文本串中)就是答案。时间复杂度大概为O((|A|+|B|)*log(|A|+|B|))。(阅兵假期用来搞这个,感觉还是有点怪怪的感觉,不过秉承着以前的学习风格,先记下模板,以后在水题中慢慢体会好了)

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <algorithm>
     5 using namespace std;
     6 typedef long long LL;
     7 const int maxn = 200010;
     8 
     9 int sa[maxn], rank[maxn], height[maxn];
    10 int t1[maxn], t2[maxn], r[maxn], c[maxn];
    11 bool cmp (int *str, int a, int b, int k)
    12 {//rank相邻的两个串,第一第二关键字都一样,rank一样
    13     return str[a]==str[b] && str[a+k]==str[b+k];
    14 }
    15 int da (int *str, int n, int m)
    16 {
    17     int *x = t1, *y = t2, i, j;
    18     n ++;
    19     //基数排序,
    20     for (i=0; i<m; i++) c[i] = 0;
    21     for (i=0; i<n; i++) c[x[i] = str[i]] ++;
    22     for (i=1; i<m; i++) c[i] += c[i-1];
    23     for (i=n-1; i>=0; i--) sa[-- c[str[i]]] = i;
    24     for (j=1; j<=n; j*=2)
    25     {
    26         //用sa数组对第二关键字排序
    27         int p = 0;
    28         for (i=n-j; i<n; i++) y[p++] = i;  //不能添加长度为j的串,第二关键字附为最小
    29         for (i=0; i<n; i++) if (sa[i] >= j) y[p++] = sa[i] - j;
    30         //枚举rank,起点大于j的串,才能倍增
    31         //更新sa数组
    32         for (i=0; i<m; i++) c[i] = 0;
    33         for (i=0; i<n; i++) c[x[y[i]]] ++;
    34         for (i=1; i<m; i++) c[i] += c[i-1];
    35         for (i=n-1; i>=0; i--) sa[-- c[x[y[i]]]] = y[i];
    36         //更新x数组
    37         swap (x, y);
    38         p = 1, x[sa[0]] = 0;
    39         for (i=1; i<n; i++)
    40             x[sa[i]] = cmp(y, sa[i-1], sa[i], j)?p-1:p++;
    41         if (p >= n)
    42             break;
    43         m = p;
    44     }
    45     //计算rank数组
    46     for (i=0; i<n; i++)
    47         rank[sa[i]] = i;
    48     //计算height数组
    49     n --;
    50     int k = 0;
    51     for (i=0; i<n; i++)
    52     {//枚举起点, height[名次]
    53         if (k)  k --;
    54         j = sa[rank[i]-1];
    55         while (str[i+k]==str[j+k])    k++;
    56         height[rank[i]] = k;
    57     }
    58 }
    59 int main ()
    60 {
    61     char str1[maxn/2], str2[maxn/2];
    62     while (scanf ("%s %s", str1, str2) != EOF)
    63     {
    64         int n1 = strlen(str1);
    65         int n2 = strlen(str2);
    66         int n = n1 + n2 + 1;
    67         for (int i=0; i<n; i++)
    68         {
    69             if (i < n1)
    70                 r[i] = str1[i];
    71             else if (i == n1)
    72                 r[i] = '$';
    73             else
    74                 r[i] = str2[i-n1-1];
    75         }
    76         r[n] = 0;
    77         da (r, n, 128);
    78         int ans = 0;
    79         for (int i=1; i<n; i++)
    80         {//i为rank
    81             if (sa[i]<n1&&sa[i-1]>n1 || sa[i]>n1&&sa[i-1]<n1)
    82                 //rank相邻的后缀串不在同一个字符串
    83                 ans = max(ans, height[i]);
    84         }
    85         printf ("%d
    ", ans);
    86     }
    87     return 0;
    88 }
    本文为博主原创文章,未经博主允许不得转载。
  • 相关阅读:
    Java21-统计字符串中每个字符出现的次数
    算法练习之字符串切割及统计每个字符出现的次数
    Java20-HashMap
    Java19-hashSet
    Java18-泛型的基础知识
    Java17-foreach循环遍历
    Java16-【转载】ArrayList和LinkedList的区别
    Unity查看Editor下PlayerPrefs信息
    Unity下自定义快捷键创建UGUI元素
    Unity中去除贴图中多余的透明区域
  • 原文地址:https://www.cnblogs.com/alihenaixiao/p/4782025.html
Copyright © 2011-2022 走看看