算法提高 第一期 KMP扩展算法

ops/2024/10/20 14:49:19/

1## 具体思路:
和KMP算法的是想类似,充分利用已经比较字符性质来减少冗余的字符比较次数。KMP的思想是充分的利用模式串中所有前缀字串(以模式串为开头的字串)的真前缀和真后缀(指子串的开始字符与子串的最后字符相等的个数)来减少不必要的字符比较,真前缀和真后缀相等的个数保存在next数组中。扩展KMP算法则是利用子串T中的所有后缀子串suffix[i]与字串T的最长公共前缀来减少字符的比较次数,这个最长公共前缀的个数也记录在next数组中。

假设我们已经求出了extend[0…k]并且记录了a和p,p表示在S串中从第i(i=0…k)个字符开始匹配的过程中达到的最远的位置,a表示取p这个最大值所对应的i值。现在求extend[k+1],可以分下面三种情况:

k+1==p(p肯定是大于或等于k+1的)
 直接S[k+1]与T[0]开始比较,并更新a和p的值
k + 1 + next[k - a + 1] <= p
 extend[k+1] = next[k - a + 1]
k + 1 + next[k - a + 1] > p
直接S[p]与T[p - k -1]开始比较,extend[k+1]也对应的从p - k - 1开始往后加,并更新a和p的值
  对于第二种和第三种情况怎么得到的呢?这就要靠我们保存的a和p了。如果p > k + 1,那么必然有S[k+1,p-1] = T[k-a+1,p-a],这个可以通过S[a,p-1] = T[0,p-a]推出。我们在next[k-a+1]中保存了T的suffix[k-a+1]子串与T的最长公共前缀的长度,假设L=next[k-a+1],那么T[k-a+1,k-a+L]=T[0,L-1]。如果k+1+L<= p,通过S[k+1,p-1] = T[k-a+1,p-a],可以得到S[k+1,k+L]=T[k-a+1,k-a+L]=T[0,L-1],并且S[k+L+1]!=T[0,L]的(因为如果相等的话,T[k-a+1,k-a+L+1]=T[0,L],这与前面的T[k-a+1,k-a+L]=T[0,L-1]是矛盾的),所以extend[k+1]=L。如果k+1+L> p,那么S[k+1,p-1] = T[k-a+1,p-a]=T[0,p-k-2],所以extend[k+1]至少等于p-k-1,然后我们应该继续从p开始比较,因为从p开始都是没有比较过的。

求next的思路和求extend的思路是一样的,只不过是T对自己求extend。

模板:

for(int i = 2; i <= m + n; i ++){if(i <= r) z[i] = min(z[i - l + 1], r - i + 1);while(s[1 + z[i]] == s[i + z[i]]) z[i] ++;if(i + z[i] - 1 > r) l = i, r = i + z[i] - 1; }

例题:

在这里插入图片描述

AC代码:

#include<bits/stdc++.h>using namespace std;typedef long long ll;
typedef pair<int, int>PII;
const int N=3e5+10;
const int MOD = 1e9 + 7;
const int INF=0X3F3F3F3F;
const int dx[]={-1,1,0,0,-1,-1,+1,+1};
const int dy[]={0,0,-1,1,-1,+1,-1,+1};
const int M = 1e6 + 10;int z[1001000];
int n, m;int main()
{cin >> n;string a, b;cin >> a;cin >> m;cin >> b;string s = ' ' + a + b;int l = 1, r = 0;z[1] = n + m;//n小m大for(int i = 2; i <= m + n; i ++){if(i <= r) z[i] = min(z[i - l + 1], r - i + 1);while(s[1 + z[i]] == s[i + z[i]]) z[i] ++;if(i + z[i] - 1 > r) l = i, r = i + z[i] - 1; }for(int i = n + 1; i <= m + n; i ++){if(z[i] == n) cout << i - n - 1 << " ";}return 0;
}

http://www.ppmy.cn/ops/23956.html

相关文章

verilog分析task的接口设计,证明这种写法:assign {a,b,c,d} = links;

verilog分析task的接口设计&#xff0c;证明这种写法&#xff1a;assign {a,b,c,d} links; 1&#xff0c;task在状态机中的使用好处&#xff1a;2&#xff0c;RTL设计3&#xff0c;测试testbench4&#xff0c;波形分析&#xff0c;正确&#xff01; 参考文献&#xff1a; 1&am…

2024.04.10校招 实习 内推 面经

绿*泡*泡VX&#xff1a; neituijunsir 交流*裙 &#xff0c;内推/实习/校招汇总表格 1、校招 | 蔚来校招 硬核造车&#xff0c;等你投递&#xff08;内推&#xff09; 校招 | 蔚来校招 硬核造车&#xff0c;等你投递&#xff08;内推&#xff09; 2、校招 | 华大半导体2024…

如何一键清除文件目录下所有的node_modules

如何一键清除文件目录下所有的node_modules 快速删除目录下的node_modules&#xff0c;下面附上windows和mac的脚本指令 windows脚本 FOR /d /r . %d in (node_modules) DO IF EXIST "%d" rm -rf "%d"mac脚本 find . -name "node_modules" -…

React的状态管理useState

基础使用 useState 是一个 React Hook&#xff08;函数&#xff09;&#xff0c;它允许我们向组件添加一个状态变量, 从而控制影响组件的渲染结果和普通JS变量不同的是&#xff0c;状态变量一旦发生变化组件的视图UI也会跟着变化&#xff08;数据驱动视图&#xff09; useState…

【Docker】常见命令汇总

1 镜像相关 1.1 查看镜像 # 查看镜像列表 docker images# 查看具体的镜像: sudo docker images <镜像名称> docker images centos # 指定具体 tag: sudo docker images centos:<tag> docker images centos:7.8.2003# 查看镜像 ID 列表: --q/--quiet docker ima…

gateway全局token过滤器

添加gateway依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency>创建一个tokenFilter 实现全局过滤器GlobalFilter,并且实现fitler方法 Value("${…

关于discuz论坛网址优化的一些记录(伪静态)

最近网站刚上线&#xff0c;针对SEO做了些操作&#xff0c;为了方便网站网页被收录&#xff0c;特此记录下 1.开启伪静态 按照操作勾选所有项&#xff0c;然后点击查看伪静态规则 2.打开宝塔&#xff0c;找到左侧列表的网站&#xff0c;然后找到相应站点的设置。把discuz自动…

iOS AVPlayer

参考文章 AVPlayer的基本使用