SP1811

题目描述

A string is finite sequence of characters over a non-empty finite set Σ.

In this problem, Σ is the set of lowercase letters.

Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string.

Now your task is simple, for two given strings, find the length of the longest common substring of them.

Here common substring means a substring of two or more strings.

输入格式

The input contains exactly two lines, each line consists of no more than 250000 lowercase letters, representing a string.

输出格式

The length of the longest common substring. If such string doesn’t exist, print “0” instead.

题意翻译

输入2 个长度不大于250000的字符串,输出这2 个字符串的最长公共子串。如果没有公共子串则输出0 。

Translated by @xyz32768

输入输出样例

输入

alsdfkjfjkdsal

fdjskalajfkdsla

输出

3

有两个字符串AAA和BBB,我们要求它们的最长公共连续子串。

首先,我们对AAA建立一个SAMSAMSAM。

定义:LenLenLen为当前BBB的前iii个字符组成的子串与AAA的最长公共子序列,StateStateState为当前状态,初始化为0(初始状态)。next(State,ch)next(State,ch)next(State,ch)为在StateStateState状态节点处往chchch道路走的下一状态。

匹配

然后我们从B[i=0]B[i=0]B[i=0]开始,在AAA的SAMSAMSAM上走,一个一个匹配,若:

  1. 当前状态朝着B[i]B[i]B[i]往下走有路,说明可以继续往下匹配,就接着走,即State=next(State,B[i]),++LenState=next(State,B[i]),++LenState=next(State,B[i]),++Len。
  2. 如果没有路了,就跳到当前状态在后缀连接树上的父节点,如果父节点还是没有B[i]B[i]B[i]的路,就一直往上跳(即State=link(State)State=link(State)State=link(State)),直到遇到能往下走的边。此时就令Len=len(当前状态)+1Len=len(当前状态)+1Len=len(当前状态)+1,State=next(State,B[i])State=next(State,B[i])State=next(State,B[i])。
  3. 如果跳到头了都没有能走的路的话,就说明要从B[i]开始重新匹配,令Len=0,State=0Len=0,State=0Len=0,State=0。

原理:如果B[i]B[i]B[i]在当前位置下失配(无路可走),那么说明当前状态下的所有子串都失配了,但是它的后缀连接树上的父节点不一定失配,就继续往上找,即相当于当前已经匹配的AAA的子串的左边界往右移,然后继续找路。如果一直没路,就一直往上找,直到达到 初始状态 ,如果此时仍没有路的话,说名在当前LenLenLen长度下已经是B[上一次从初始状态开始匹配的i]B[上一次从初始状态开始匹配的i]B[上一次从初始状态开始匹配的i]开始的最长公共子串了,无法在加长了。那就让Ans=max(Ans,Len)Ans=max(Ans,Len)Ans=max(Ans,Len),让后以B[i]B[i]B[i]为新的开头从初始状态重新开始匹配。即整个过程就是再找BBB的所有前缀的后缀最长能和AAA匹配多少。

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
const int MAXN = 250005;
int n;
char
A[MAXN],
B[MAXN];
struct SAM {
int size, last;
struct Node {
int len = 0, link = 0;
int next[26];
void clear() {
len = link = 0;
memset(next, 0, sizeof(next));
}
} node[MAXN * 2];
void init() {
for (int i = 0; i < size; i++) {
node[i].clear();
}
node[0].link = -1;
size = 1;
last = 0;
}
void insert(char x) {
int ch = x - 'a';
int cur = size++;
node[cur].len = node[last].len + 1;
int p = last;
while (p != -1 && !node[p].next[ch]) {
node[p].next[ch] = cur;
p = node[p].link;
}
if (p == -1) {
node[cur].link = 0;
}
else {
int q = node[p].next[ch];
if (node[p].len + 1 == node[q].len) {
node[cur].link = q;
}
else {
int clone = size++;
node[clone] = node[q];
node[clone].len = node[p].len + 1;
while (p != -1 && node[p].next[ch] == q) {
node[p].next[ch] = clone;
p = node[p].link;
}
node[q].link = node[cur].link = clone;
}
}
last = cur;
}
}sam;
int getNextState(const int& CurState,int Loc) {
return sam.node[CurState].next[Loc - 'a'];
}
int Compute(int n) {
int
&& Ans = 0,
&& CurState = 0,
&& Len = 0;
for (int i = 0; i < n; ++i) {
//如果有路可走,就走噻
if (getNextState(CurState, B[i])) {
CurState = getNextState(CurState, B[i]);
++Len;
}
//否则
else {
//跳link
for (CurState = sam.node[CurState].link;; CurState = sam.node[CurState].link) {
//如果跳到了
if (CurState > 0 && getNextState(CurState, B[i])) {
Len = sam.node[CurState].len + 1;
CurState = getNextState(CurState, B[i]);
break;
}
//如果跳到初始状态。
else if (CurState <= 0) {
Len = 0;
CurState = 0;
break;
}
}
}
Ans = max(Ans, Len);
}
return Ans;
}
int main() {
scanf("%s%s", &A, &B);
int Len_A = strlen(A);
sam.init();
for (int i = 0; i < Len_A; ++i) {
sam.insert(A[i]);
}
printf("%d", Compute(strlen(B)));
return 0;
}

Longest Common Substring(最长公共子串)的更多相关文章

  1. lintcode 77.Longest Common Subsequence(最长公共子序列)、79. Longest Common Substring(最长公共子串)

    Longest Common Subsequence最长公共子序列: 每个dp位置表示的是第i.j个字母的最长公共子序列 class Solution { public: int findLength ...

  2. hdu 1403 Longest Common Substring(最长公共子字符串)(后缀数组)

    http://acm.hdu.edu.cn/showproblem.php?pid=1403 Longest Common Substring Time Limit: 8000/4000 MS (Ja ...

  3. LCS(Longest Common Subsequence 最长公共子序列)

    最长公共子序列 英文缩写为LCS(Longest Common Subsequence).其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已 ...

  4. poj 1458 Common Subsequence_最长公共子串

    题意:略 求最长公共子串 #include<iostream> #include<cstdio> #include<string> using namespace ...

  5. LCS(Longest Common Subsequence)最长公共子序列

    最长公共子序列(LCS)是一个在一个序列集合中(通常为两个序列)用来查找所有序列中最长子序列的问题.这与查找最长公共子串的问题不同的地方是:子序列不需要在原序列中占用连续的位置 .最长公共子序列问题是 ...

  6. 【LeetCode】14. Longest Common Prefix 最长前缀子串

    题目: Write a function to find the longest common prefix string amongst an array of strings. 思路:求最长前缀子 ...

  7. [LeetCode]14. Longest Common Prefix最长公共前缀

    Write a function to find the longest common prefix string amongst an array of strings. If there is n ...

  8. # Leetcode 14:Longest Common Prefix 最长公共前缀

    公众号:爱写bug Write a function to find the longest common prefix string amongst an array of strings. If ...

  9. 【LeetCode】14. Longest Common Prefix 最长公共前缀

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:prefix, 公共前缀,题解,leetcode, 力扣 ...

  10. Leetcode No.14 Longest Common Prefix最长公共前缀(c++实现)

    1. 题目 1.1 英文题目 Write a function to find the longest common prefix string amongst an array of strings ...

随机推荐

  1. C++的switch/case,需要大括号

    如果,switch/case的某一条case语句包含初始化定义变量,例如int i. 那么case后面的语句,需要用大括号包装起来. 原因如下: https://stackoverflow.com/q ...

  2. charles小程序抓包

    参考链接:https://www.jianshu.com/p/048b67c5ed00 1. 手机上的程序目前按app的抓包方式,配置代 理,下载证书,打开设备---微信---本地网络,就可以直接抓包 ...

  3. js 评论时间换算

    //时间戳换算 let dateTime=2020-10-10 10:10:10 getDateDiff(dateTime){ let dateTimeStamp = new Date(dateTim ...

  4. SpringBoot配置阿里云https提示端口占用问题

    1.因为要配置https,所以去网上找了一些资料,然后按照步骤,依次完成了以下步骤 ①在application.yml中加入配置 http: port: 12000 #原本的端口号server: po ...

  5. ubuntu启动盘制作

    转自https://www.cnblogs.com/silentdoer/p/13044305.html 1. 从Ubuntu官网http://cn.ubuntu.com/download/下载系统的 ...

  6. Centos安装后出现please make your choice from '1' to eter the license information spoke | 'q' to quit |'c' to continue |'r' to refresh

    这是要求用户阅读或者接收协议: 解决方法:输入"1",按Enter键   阅读许可协议,输入"2",按Enter键  接受许可协议,输入"q" ...

  7. keypress和keydown的区别

    keypress不识别功能键,比如ctrl,alt,shift,上下左右.keypress返回的ascII码区分大小写.输入小写a返回97,输入大写A返回65. keydown识别.keydown返回 ...

  8. EIRENE GSM-R编码计划

    Numbering plan overview This appendix provides an overview of the numbering plan as defined in this ...

  9. Hbase 报错hbase Could not start zk requested port of 2181

    windows下面   解决: 1. conf/hbase-env.cmd set HBASE_MANAGES_ZK=false 2. 先启动Hbase start-Hbase.cmd 再启动 zoo ...

  10. golang 指针

    一个指针变量指向了一个值的内存地址,类似于变量和常量,在使用指针前你需要声明指针. 每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置.使用&字符放在变量前面对变量进行" ...