字符串(字符串匹配)

article/2025/10/4 1:08:04

一、字符串匹配问题、基础

1、假设文本是一个长度为n的数组T,而模式是长度为m的数组P,我们希望在文本T中寻找模式P

如果P出现在T中的第s个位置,那么我们称其有效偏移为s,在其他不匹配的位置称为无效偏移

2、如果字符串w是字符串x的前缀,可以记作w\sqsubset x,后缀可以记为w\sqsupset x

引理:如果x、y都是z的后缀,如果x.size<y.size那么x是y的后缀;如果x.size=y.size则x=y

3、如果应用暴力匹配,那么对每个偏移量都会进行匹配,那么复杂度O((n-m+1)m)

二、Rabin-Karp算法

1、利用字符串的hash值进行匹配,而不是逐位进行比较。在计算hash值时,可以先计算出模式串长度的hash值,然后前面“减”一位,后面“加”一位,可以求出母串所有长为m的hash值,进而匹配

2、如果hash值过大,可以进行取模,那么可能出现hash冲突,此时需要进行显示匹配(如果hash值不同那么一定不匹配)。此时的算法是在快速检测无效偏移

三、有限自动机

自动机用通俗的话讲,就是不断向一个机器里面输入内容,然后机器会根据现在的状态和输入的内容达到下一个状态。

一个有限自动机M,是一个五元组(Q,q_0,A,\sum ,\delta )其中,

Q是状态的有限集合;(可能出现的状态)

q_0\in Q是初始状态;(最开始的状态)

A\subseteq Q是一个特殊的接收状态集合;(满足题意的状态)

\;\sum是有限输入集合;(可能的输入)

\delta是一个从Q\times\sumQ的函数,称为M的转移函数;(从一个状态转向另一个状态的函数)

有限自动机开始于状态q_0,每次读入一个字符,如果在状态q是读入字符a,那么他会从状态q变成状态\delta (q,a)(进行了一次转移),当q\in A时,就说自动机M接受了迄今为止所读入的字符串,没有被接受的输入称为被拒绝的输入

 如上图就是模式串ababaca的状态转换图

四、KMP算法

1、匹配原理

为了减少重复过程,可以选择j来优化匹配位置,而j取决于当前字符之前的串的前后缀的相似度,而这个前后缀的相似度就用next数组来记录

如果前缀和后缀相同,就用前缀对齐后缀,下一位从字符开始重新匹配

匹配的过程可以利用有限状态自动机来理解

2、next数组

含义:从第j(字符串和下标j从0开始)个(不包括j)向前k个元素与从第1个向后k个元素相同,k就是next[j]的值

换种解释方法:next[i](字符串和下标i从1开始)表示s中以s[i]结尾的非前缀子串与s的前缀能匹配的最长长度

next数组从0到len,一共有len+1个位置,第一个位置0对应字符串第一个位置,最后一个位置len对应字符串的尾后位置(next数组此时对应是前面整个字符串能匹配的最长前后缀)

3、求next数组

如果j == -1就开始向前匹配,如果s[i] == s[j]填next数组并向后匹配

if (j == -1 || s[i] == s[j])nex[++i] = ++j;

 如果没有匹配上,就到s[j]的前面的字符串的能匹配到的最长的前后缀

比如:abac......abax,i到x位置,j到c位置,不相等,那么就到nex[3]=1位置

elsej = nex[j];

4、代码 

//以-1开头的next数组中存的是匹配失败时要去字符串的下标(该下标前nex[j]个无需重复匹配)
int nex[maxn];
void getnext(string s)
{int i, j;i = 0; j = -1;nex[0] = -1;while (i < s.size()){if (j == -1 || s[i] == s[j])nex[++i] = ++j;elsej = nex[j];}
}
int kmp(string a, string b)		//a母串,b模式串
{int ans = 0;getnext(b);int i = 0, j = 0;while (i < a.size()){if (j == -1 || b[j] == a[i]){++i;++j;}else j = nex[j];if (j == b.size()){ans++;j = nex[j];}}return ans;
}


http://chatgpt.dhexx.cn/article/VyWWEQkc.shtml

相关文章

字符串匹配

字符串匹配 1.朴素的串匹配算法(暴力解法) 1.1 分析 设t是目标串&#xff08;母串&#xff09;&#xff0c;p是模式串&#xff08;待匹配串&#xff09;&#xff0c;i , j 分别指向 模式串 和 目标串&#xff0c;m、n分别是模式串p和目标串t的长度。 从目标串的第0个字符&am…

Photoshop怎么给图片添加简介信息或者版权信息

转自&#xff1a;Photoshop怎么给摄影图片添加作者名字版权等信息? 有时我们点开一张图片的详细信息中可能可以看到各种属性信息&#xff0c;比如作者&#xff0c;时间&#xff0c;关键字&#xff0c;图片信息描述等属性&#xff0c;但是我们自己的拍摄的或者从别的地方获取的…

2022年中国版权保护中心计算机软件著作权登记最全申请步骤流程

一、前言二、实名认证1. 用户注册2. 实名认证 三、办理步骤1. 办理流程2. 填写申请表3. 提交申请文件4. 登记机构受理申请5. 审查6. 获得登记证书 四、登记申请所需文件1. 软件著作权登记申请表2. 软件&#xff08;程序、文档&#xff09;的鉴别材料3. 有关证明文件 五、申请表…

IDEA设置版权信息

File→Settings或者CtrlS快捷键。 Editor下面有个Copyright→Copyright Profiles 点击加号&#xff0c;然后输入名称。 然后修改成自己的信息&#xff1a; 其中第一个年份是本文件新建日期&#xff0c;后面的是最后一次修改年份。 中文版本&#xff1a; 版权所有(c) Jack魏 …

版权和版本信息

版权和版本信息的主要内容有&#xff1a; &#xff08;1&#xff09;版权信息&#xff1b; &#xff08;2&#xff09;文件名称、简要描述、创建日期和作者&#xff1b; &#xff08;3&#xff09;当前版本信息和说明&#xff1b; &#xff08;4&#xff09;历史版本信息和…

版权和商标权有什么关系?版权和商标的区别在哪里?

版权和商标权存在着一定的关系&#xff0c;版权和商标又有着很多区别&#xff0c;具体的关系和区别是怎样的&#xff0c;大家都知道吗&#xff1f;今天企多多就带大家来了解&#xff01; 版权和商标权的关系 版权和商标权的关系主要有以下三点&#xff1a; 1、关联性&#xf…

版权 | 收藏!哪些作品可以登记版权?

创业创新中&#xff0c;无论是公司LOGO还是IP形象或者产品手册&#xff0c;都凝结着无数的心血。当下互联网和科技的发展&#xff0c;让抄袭变得前所未有的容易&#xff0c;尤其在美术作品、文字作品和影视作品领域。如何有效地保护自己的智力成果呢&#xff1f;先从了解这些开…

Pyinstaller加入版本和版权信息

目录 参考链接 前言 一. 获取版本信息 1. 拖过来个有版本和版权信息的exe文件 2. 放置一个txt文件 我们接着放置一个txt文件叫file_version_info.txt。这名字不能改&#xff0c;Pyinstaller自动就把版权信息放在这里。 3.开始获取 二. 修改 三. 打包 参考链接 pyinsta…

版权信息的生成方法

网页底部添加网站的版权信息&#xff0c;将版权信息封装到JavaBean中&#xff0c;可重复利用 新建JavaBean类 public class StringUtil3 {private String copyrightStr"xxxxxxxxxxx xxxxxxxxxxxxx--xxxxxxxxxxxxxxxxxxxx-xxx";public String getCopyrightStr() {ret…

C++虚函数表

一、背景知识&#xff08;一些基本概念&#xff09; 虚函数&#xff08;Virtual Function&#xff09;&#xff1a;在基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数。 纯虚函数&#xff08;Pure Virtual Function&#xff09;&#xff1a;基类中没有实现体…

虚函数和虚函数表

多态是由虚函数实现的&#xff0c;而虚函数主要是通过虚函数表&#xff08;V-Table&#xff09;来实现的。 如果一个类中包含虚函数&#xff08;virtual修饰的函数&#xff09;&#xff0c;那么这个类就会包含一张虚函数表&#xff0c;虚函数表存储的每一项是一个虚函数的地址…

C++ 虚函数表 vfptr

前言 大家都应该知道C的精髓是虚函数吧? 虚函数带来的好处就是: 可以定义一个基类的指针, 其指向一个继承类, 当通过基类的指针去调用函数时, 可以在运行时决定该调用基类的函数还是继承类的函数. 虚函数是实现多态(动态绑定)/接口函数的基础. 可以说: 没有虚函数, C将变得一…

c++ 虚函数及虚函数表

多态”的关键在于通过基类指针或引用调用一个虚函数时&#xff0c;编译时不确定到底调用的是基类还是派生类的函数&#xff0c;运行时才确定。 #include <iostream> using namespace std; class A { public:int i;virtual void func() {}virtual void func2() {} }; cla…

虚函数表结构

虚函数表 所谓虚函数表就是存放着当前类中所有虚函数地址的表。在实例化一个具有虚函数的类时&#xff0c;这个表也被分配到这个实例对象的内存中&#xff0c;通过虚函数表可以指明所要调用的函数的位置。在C编译器中虚函数表的地址存放在对象的最前面&#xff0c;这是为了即使…

关于虚函数与虚函数表

首先&#xff0c;我们知道&#xff0c;C的动态多态是基于虚函数实现的 。 C能够在运行时确定调用的函数是因为引入了虚函数&#xff0c;在类中引入虚函数后,在程序编译期间就会创建虚函数表&#xff0c;表中每一项数据都是虚函数的入口地址。 然而&#xff0c;怎么才能访问到虚…

C++中的虚函数表

引言&#xff1a; 多态对于C这种面向对象的语言来讲&#xff0c;其重要性是不言而喻的&#xff0c;用了足足半天的时间来把我所理解的多态表达出来&#xff0c;其中还有很多细节需要以后补充。&#xff08;一个字一个字写&#xff0c;还要画图&#xff0c;太累了&#xff09; …

虚函数原理与虚函数表

目录 一、 虚函数 二、虚函数原理与虚函数表 一、 虚函数 虚函数&#xff1a; 使用 virtual 关键字声明的函数&#xff0c;是动态多态实现的基础。 非类的成员函数不能定义为虚函数。 类的静态成员函数不能定义为虚函数。 构造函数不能定义为虚函数&#xff0c;但可以将析构函…

c++虚函数和虚函数表

什么是虚函数? 用virtual 修饰的成员函数叫虚函数 没有虚构造函数 不写虚函数&#xff0c;没有默认的虚函数 虚函数对于类的影响&#xff1a;增加一个指针的内存 虚函数的存储&#xff1a;虚函数表(了解内容&#xff1a;就是一个指针存储所有虚函数的首地址[函数指…

虚函数表存储位置

前言 先说结论&#xff1a;虚函数表存储在只读数据段&#xff08;.rodata&#xff09;、虚函数存储在代码段&#xff08;.text&#xff09;、虚表指针的存储的位置与对象存储的位置相同&#xff0c;可能在栈、也可能在堆或数据段等。 相信大家知道虚表指针和虚函数存储的位置…

C++虚函数表详解

C的虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中&#xff0c;主要是一个类的虚函数的地址表&#xff0c;这张表解决了继承、覆盖(override)的问题&#xff0c;保证其能真实的反应实际的函数。这样&#xff0c;在有虚函数的类…