首页 > 其他分享 >【学习笔记】KMP

【学习笔记】KMP

时间:2024-07-31 19:30:12浏览次数:8  
标签:lb int 笔记 学习 ++ KMP 字符串 pi

【学习笔记】KMP

因为字符串对我太抽象了,所以只能以水的心态写这个 KMP。

感觉考到字符串的题肯定要崩。

以下均规定字符串 \(S\) 以下标 0 开头。

前缀函数:
给定一个长度为 \(n\) 的字符串 \(S\),其前缀函数被定义为一个长度为 \(n\) 的数组 \(\pi\)。
简单来说 \(\pi[i]\) 就是,子串 \(s[0\dots i]\) 最长的相等的真前缀(即不包括字符串 \(s\) 本身的前缀)与真后缀的长度。

周期:
若 \(S[i]=S[i+p]\) 对 \(i=0,\ldots,n-1-p\) 均成立,则 \(p\) 是 \(S\) 的一个周期。\((1\leq p\leq n)\)

border:
若 \(S[ : r) = S[-r: )\),则 \(r\) 是 \(S\) 的一个 border 的长度。\((0\leq r< n)\)
注意到存在 border \(r\) 等价于存在周期 \(p= N-r\)。

可以发现 \(\pi[n]\) 就 是 最 大 的 border。
进一步地 \(S\) 的所有 border 为 \(\pi[n], \pi[\pi[n]], \pi[\pi[\pi[n]]], \ldots\)
换句话说,利用 \(\pi\) 可以求出 \(S\) 的所有周期。

思路(求 \(\pi\) 数组):

  • 对于 \(1\leq i<n\),有 \(\pi[i+1]\leq\pi[i]+1\)。
    实际上 \(\pi[i+1]=\pi[i]+1\) 当且仅当 \(S[i]=S[\pi[i]]\)。

  • 对于 \(S[i]\neq S[\pi[i]]\) 的情形,我们需要找到最大的 \(j<\pi[i]\) 使得 \(S[:j)=S[i-j:i)\) 且 \(S[i]=S[j]\)。

  • 可以不断地令 \(j\leftarrow\pi[j]\) 直至找到满足 \(S[:j)=S[i-j:i)\) 且 \(S[i]=S[j]\) 的 \(j\)。

附赠字符串下标从 1 开始KMP模板(绝对不是因为从 0 开始写挂了)

\(\pi\) 数组即为 \(nxt\) 数组。

注意如何比对两个字符串。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e6+5;

int nxt[N];

int main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	string s1, s2; cin>>s1>>s2;
	int len1 = s1.length(), len2 = s2.length();
    s1 = ' '+s1, s2 = ' '+s2;
	for(int i=2; i<=len2; i++){
		nxt[i] = nxt[i-1];
		while(nxt[i] && s2[nxt[i]+1]!=s2[i]) nxt[i] = nxt[nxt[i]];
		if(s2[nxt[i]+1]==s2[i]) nxt[i]++;
	}
	for(int i=1, j=0; i<=len1; i++){
        // j 是已经匹配完的模式串的最后一位的位置
        while(j && s1[i]!=s2[j+1]) j=nxt[j];
        if(s1[i]==s2[j+1]) j++;
        if(j==len2){
            cout<<i-len2+1<<"\n";
            j = nxt[j]; // 继续匹配
        }
    }
    for(int i=1; i<=len2; i++)
        cout<<nxt[i]<<" ";
	return 0;
}

因为我太菜了,所以 0 下标开始的只能附赠巨佬 @ysl_wf 的代码:
%%%%%%%%%%%%stO巨佬Orz%%%%%%%%%%%%%%

#include<bits/stdc++.h>
using namespace std;

typedef long long lt;
const lt N = 1e6 + 10;
lt pi[N];
lt la, lb, j;
char a[N], b[N];

int main(){
    cin >> a;
    cin >> b;
    la = strlen(a), lb = strlen(b);
    j = -1; pi[0] = -1;
    for(int i = 1; i < lb; i++){
        while(j >= 0 && b[i] != b[j+1]) 
            j = pi[j];
        if(b[j+1] == b[i]) 
            j++;
        pi[i] = j;
    }
    j = -1;
    for(int i = 0; i < la; i++){
        while(j >= 0 && b[j+1] != a[i])
            j = pi[j];
        if(b[j+1] == a[i])
            j++;
        if(j == lb-1){
            printf("%lld\n", i-lb+2);
            j = pi[j];
        }
    }
    for(int i = 0; i < lb; i++){
        printf("%lld ", pi[i]+1);
    }
}

标签:lb,int,笔记,学习,++,KMP,字符串,pi
From: https://www.cnblogs.com/FlyPancake/p/18335290/KMP

相关文章

  • 后缀数组学习笔记
    前言后缀数组(SuffixArray,简称SA)是一种解决某些字符串问题的常用工具。解决这些字符串问题时,经常用后缀数组对问题进行一定的转化成其它的模型,然后套用那个模型的解决方法加以解决原问题。附题单约定本文做以下约定:本文撰写时间跨度较大,有些符号会出现正体、斜体混用的情......
  • 业务逻辑学习!
    获取地址列表方法传入一个token参数,首先解析获取token信息获取用户id构建查询条件,指定查询的用户id设置查询结果按照地址进行降序调用dao层查询然后返回查询条件为启用的json数组首先创造查询条件,条件为1的,即状态为启用的调用dao层进行查询返回一个数组对象遍历......
  • 【C++】构造函数的深入学习
    一、初始化列表C++提供初始化列表语法用来初始化属性语法:构造函数():属性1(值1),属性2(值2)...{}classPeople{public://传统初始化操作Person(inta,intb,intc){A=a;B=b;C=c;}//初始化列表初始化属性Pers......
  • MySQL 学习笔记 进阶(锁 下,InnoDB引擎 上)
    锁 锁-表级锁-表锁介绍表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在MyISAM,InnoDB,BDB等存储引擎中。对于表级锁,主要分为以下三类:表锁元数据锁(metadatalock,MDL)意向锁表锁对于表锁,分为两类:表共享读锁(readlock)表独占写锁(write......
  • 网络安全自学入门:(超详细)从入门到精通学习路线&规划,学完即可就业
    很多人上来就说想学习黑客,但是连方向都没搞清楚就开始学习,最终也只是会无疾而终!黑客是一个大的概念,里面包含了许多方向,不同的方向需要学习的内容也不一样。算上从学校开始学习,已经在网安这条路上走了10年了,无论是以前在学校做安全研究,还是毕业后在百度、360从事内核安全产品......
  • 网络安全自学入门:(超详细)从入门到精通学习路线&规划,学完即可就业
    很多人上来就说想学习黑客,但是连方向都没搞清楚就开始学习,最终也只是会无疾而终!黑客是一个大的概念,里面包含了许多方向,不同的方向需要学习的内容也不一样。算上从学校开始学习,已经在网安这条路上走了10年了,无论是以前在学校做安全研究,还是毕业后在百度、360从事内核安全产品......
  • 网络安全自学入门:(超详细)从入门到精通学习路线&规划,学完即可就业
    很多人上来就说想学习黑客,但是连方向都没搞清楚就开始学习,最终也只是会无疾而终!黑客是一个大的概念,里面包含了许多方向,不同的方向需要学习的内容也不一样。算上从学校开始学习,已经在网安这条路上走了10年了,无论是以前在学校做安全研究,还是毕业后在百度、360从事内核安全产品......
  • 扩展 BSGS 学习笔记
    在之前,我们学习了BSGS。设有\(a,b,m\),且\((a,m)\ne1\),求解:\[a^x\equivb\pmodm\]这玩意如何求解?把它变成BSGS能做的形式不就行了!具体的,设\(d_1=(a,m)\),若\(d_1\not|b\)则方程无解。否则我们可以得到:\[\dfrac{a}{d_1}\cdota^{x-1}\equiv\dfrac{b}{d_1}\pmod{\d......
  • STM32学习记录(七):ADC
    STM32学习记录(七):ADC模拟/数字转换器(Analog-to-digitalconverter:ADC)将模拟量转为数字量。STM32F103C8T6中的有2个12bit转换时间为1us的A/D转换器,内置了一个温度传感器,可以通过ADC读取。ADC的系统框图ADC读取温度传感器STM32内部有一个温度传感器,只有使用ADC1时,内部温度......
  • 【复健】LCA复健笔记
    LCA复健笔记展开目录目录LCA复健笔记什么是LCA怎么求LCA暴力求LCA倍增优化应用场景不适合的应用场景什么是LCA最近公共祖先/最深公共祖先,顾名思义,两个点的公共祖先中离它们最近/深度最大的那个。怎么求LCA这里使用倍增优化算法,因为之前看不懂所以我觉得应该补一下......