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. mac Big Sur 打开应用提示,您没有权限来打开应用程序

    终端输入codesign --force --deep --sign - /Applications/{AppName.app}注意{AppName.app} 替换为无法打开的应用程序名,将尝试强制签 ...

  2. lua-1-c# 执行lua文件-调用lua文件中的方法

    using UnityEngine;using System.Collections;using LuaInterface;//引入lua接口public class MyHellowWorld : ...

  3. win11装wsl ubuntu操作记录

    应用商店安装Windows Subsystem for Linux Preview ubuntu 查看已经安装的WSL版本,以及分发版对应的VERSION wsl -l -v 看到Ubuntu版本是1 ...

  4. git将自己分支上忽略已修改但不需要的提交的文件

    一:在idea上把需要提交的文件勾选上提交 二:git stash命令将余下被修改的文件存入(隐藏)暂存区 git stash 三:切换master分支合并上述分支 四:合并后再返回上述分支,git ...

  5. 10 个常用的 JS 工具库,80% 的项目都在用!

    Day.js 一个极简的处理时间和日期的 JavaScript 库,和 Moment.js 的 API 设计保持一样, 但体积仅有2KB. npm install dayjs 基本用法 import ...

  6. hdrp package导入工程

    补充: 可以直接把包提出来放一个单独文件夹 然后在package manager中load from disk,跟下面手动改效果没区别 如果发现有各种引用丢失,在工程内对包reimport下 1 需要 ...

  7. 正确引用R及R包

    R版本不断更新,为保证数据可重复性,引用R时需标注出对应的R版本.那么如何引用呢? 打开R,键入citation(),得到对应的版本引用信息. To cite R in publications us ...

  8. Vue 更改数组中的值,页面不刷新问题。解决方法+原理说明

    一.Vue 更改数组中的值,页面不刷新问题 data{ hobby:["打游戏","想静静","发呆"] } 1.错误写法(页面不刷新): ...

  9. Qt事件处理的几种方式

    Qt提供了5种事件处理和事件过滤的方法: 1.重写事件处理器函数 这是大部分情况最常用的一种,如重写 paintEvent().mousePressEvent().keyPressEvent() 等事 ...

  10. uniapp APP端 跳转微信小程序 完成微信支付功能,并回跳回来

    先保存   参考链接    完成功能在做具体记录 https://blog.csdn.net/qq_40146789/article/details/121262700?spm=1001.2101.3 ...