实用算法实现-第 8 篇 后缀树和后缀数组 [2 最长公共子串]

8.3    最长公共子串

求N个串的最长公共子串,可以转化为求一些后缀的最长公共前缀的最大值,这些后缀应分属于N个串。设N个串分别为S1,S2,S3,…,SN。

具体方法如下:

1. 建立字符串S,使得S = S1[P1]S2[P2]S3…SN-1[PN-1]SN。其中P1,P2,…,PN-1应为不同的N - 1个不在字符集中的字符,作为分隔符。插入分隔符的目的是为了防止S的后缀的公共前缀超出原有串Si的范围。

2. 求出S的后缀数组及其Height数组。可以用倍增算法,或DC3算法。

3. 将S1,S2,S3,…,SN的公共子串大小至少为A的真假表示为check(A),如果check(A) == true那么对于任意A’(A’< A),都有check(A’) == true。故此,可以对区间[0, L]二分,从而找到最大的A,使得check(A)== true成立。其中L为S1,S2,S3,…,SN中最短的字符串的长度。可知,共需调用验证函数check()的次数为O(logL)。

4. check()函数的思想为:找出一个区间[i, j],使得对任意i k j均有Height[k] ≥A,同时S1,S2,S3,…,SN中每个字符串Sp,在[i, j]中均存在q,使得SA[q]原属于Sp,即(Pq-1在S中的下标)SA[q] ≤ (Pq在S中的下标)。根据LCP定理,有LCP(i, j) ≥A。故此所有后缀SA[k](ikj)都有长度至少为A的共同前缀。进一步,由于分隔符的存在,S1,S2,S3,…,SN中所有的字符串都有长度至少为A的公共子串。

5. 寻找区间[i, j]的思想为:在区间[0, n-1]内向后枚举i,直至满足Height[i] ≥ A。然后在区间[i, n-1] 向后枚举j直至Height[i] ≥A不满足。其中n为S的长度。然判断区间[i, j]是否满足4.中条件。若满足条件,则check()函数返回true;不满足,则在区间[j, n-1]内继续向后枚举i和j,因为必有height[j] < A或者j > n-1。由于i, j只是扫描了一遍区间[0,n-1],可以知道寻找区间(即check()验证)的时间复杂度为O(n)。

8.3.1   实例

PKU JudgeOnline, 3450, Corporate Identity.

8.3.2   问题描述

给出一组字符串,求出它们的字典序最小的最长公共子串。

8.3.3   输入

3

aabbaabb

abbababb

bbbbbabb

2

xyz

abc

0

8.3.4   输出

abb

IDENTITY LOST

8.3.5   分析

bool check(int A)函数是用来判断一组字符串是不是有长度至少为A的公共子字串。findLeast()函数是check()的增强版,它在后者基础上找出了字典序最小的长度为A的公共子串。当然findLeast()比check()的速度慢,因为前者要找出所有长度至少为A的公共子串,并且从中取出字典序最小者。所以在二分A的时候,使用check()函数,在确定A的最大值之后则用findLeast()。

PKU JudgeOnline, 3080, Blue Jeans和这个题目几乎一样,只不过数据要弱很多。

8.3.6   程序

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
inline bool leq(int a1, int a2,   int b1, int b2) { // lexic. orderfor pairs
  return(a1< b1 || a1 == b1 && a2 <= b2);
}                                                  // and tripl
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值