关于字符串精确匹配

0 引子

嗯,开始之前先介绍几个概念:
目标串:也就是主串,待匹配的串。
模式串:去匹配的串。
子串:原串中的某一连续片段。
前缀:原串前面连续部分组成。
后缀:原串尾部连续部分组成
其实,不用被这些术语搞晕,更不必记忆,转化为自己的东西,理解了就好。

抛个问题先:
现在有两个字符串,其中一个是模式串abcabcacab,另一个是目标串babcbabcabcaabcabcabcacabc,用什么方法能快速判断目标串中是否包含模式串。

学习是个循序渐进的过程,学习算法尤其如此,所以我们由经典算法开始,一步一步深入。
经典的算法思想就是挨个匹配,失配了就整体对齐到下一位继续匹配。
step1:

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
b a b c b a b c a b c a b c a a b c a b c a c a b c
a b c a b c a c a b                                
N                                                  

第一位不匹配。

step2:

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
b a b c b a b c a b c a b c a a b c a b c a c a b c
  a b c a b c a c a b                              
        N                                          

第四位不匹配。

太多就不展开了,这样依次下去,最后肯定可以得出正确的结果。

哎,太容易想到的往往效率不高,经过上面的介绍,大家应该对这个问题有了自己的认识,我一直觉得,想要解决问题一定要对问题本身有深刻的认识,这也是我一直跟队友强调的。如果没有知其然,知其所以然的态度,建议不用继续看下去,毕竟下面要说的单模式匹配KMP算法和BM算法,都出来这么多年了,很多库都有封装,对于很多人来说真的是会用就行。

1 KMP算法

有时刷一些字符串相关的题时,经常会用到KMP算法,其实时间长了,自己也有点忘,就直接依靠以前的模板了,现在网络方便了,自己却变懒惰了,扪心自问:你能给一个完全没这方面基础的人,讲清楚什么是KMP算法吗?

KMP算法是三个人共同提出的,K,M,P分别是这三个人名字的首字母。KMP算法的主要思想是,利用模式串自身的信息,得到next表,next表主要用于失配时的跳跃。

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
b a b c b a b c a b c a b c a a b c a b c a c a b c
          a b c a b c a c a b                      
          Y Y Y Y Y Y Y N                          

上面是匹配过程中的一个状态,为了叙述方便,现在将模式串称P,目标串称为T,现在T[7] != P[12],观察下我们发现1. T[3~6] = P[8~11] 2. T[0~3] = T[3~6],发现这两点应该没什么难度。代换下,进一步发现T[0~3] = P[8~11],这样我们就不用像经典的算法那样,一次只跳一步,现在我们可以直接跳四步,直接去匹配第五位。

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
b a b c b a b c a b c a b c a a b c a b c a c a b c
                a b c a b c a c a b               a
                         ?                          

根据上面的结论,前四位匹配肯定成功,直接从第五位开始比较。

通过上面的分析,我们尝到了KMP思想的甜头,一次跳跃了四位,避免了很多无效的比较。仔细的观察下,上面的做法其实只用到了模式串的特性,和目标串并没什么联系,如果我们提前得到一张模式串的next表,那么失配时,不是可以直接去查表然后计算如何跳跃吗?嗯,对!关键是怎么得到这张表。

得到next表前,我们先要得到这样一张表,前缀自包含的长度,还是举个例子吧,对于上面的模式串T,我们求T[5]的前缀自包含长度,abcabcacab主要就是求T[0~4]中T[0~x] = T[4-x~4]中x的值,显然这里的x=1,那么T[5]前缀自包含的长度就是2,移动的步数 = 已匹配的长度 - 前缀自包含长度 = 5 - 2 = 3。也就是说在T[5]处失配时,直接向前跳3步,因为已经匹配的长度等于5,即T[0~4],前缀自包含长度等于2。

KMP的精髓也就next表,而next表的核心是前缀自包含长度,现在大家应该比较清晰了,梳理下思路就可以自己写出来了。

比较晚了,下面的BM算法,AC算法,WM算法先欠着。 0. 0

2 BM算法

这货的效率平均比KMP高3~4倍(要知道,KMP已经是O(n)的!),平时编辑器里的ctrl+F,grep之类的都是使用的这个算法。但是这个算法的核心和KMP没什么大的区别,只是换了种方式,再加上了一些自己的规则。

3 AC算法

多模式KMP算法。嗯,姑且这样理解吧!

4 WM算法

多模式BM算法。嗯,姑且这样理解吧!

未完待续。。。

时间: 2024-12-19 18:31:42

关于字符串精确匹配的相关文章

Linux shell】grep命令精确匹配字符串查找

需求: 精确匹配查找某个字符串 精确匹配: 例如: 在抽取字符串“48”,返回结果包含诸如484和483等包含“48”的其他字符串,实际上应精确抽取只包含48的各行. 使用grep抽取精确匹配的一种有效方式是在抽取字符串前加 \ <, 在抽取字符串后加 \ > .假定现在精确抽取48, 方法如下: #grep ' \ <48\>' filename 原文地址:https://www.cnblogs.com/mingzhang/p/11002241.html

字符串的匹配规则---正则表达式

常见规则: [字符] X-----------表示精确匹配字符 'X' \\-----------表示 '\' 反斜线字符 \n----------表示(新行标记)换行符('\u000A') \r-----------表示回车符('\u000D') [字符串] [abc]--------------表示匹配a.b或c中的任何一个即可 [^abc]------------表示匹配除了a.b和c以外的其他任意单个字符 [a-zA-Z]-----------表示匹配任意单个字母,不区分大小写 [0-9

js正则表达式验证、匹配数字、匹配字符串、匹配中文、匹配任意字符备忘录

本文转自:91博客 :原文地址:http://www.9191boke.com/235792704.html 正则表达式或“regex”用于匹配字符串的各个部分,下面是我创建正则表达式的备忘录.包括一些常用的验证.匹配数字.匹配字符串.匹配中文.匹配任意字符串. 匹配正则 使用 .test() 方法 let testString = "My test string"; let testRegex = /string/; testRegex.test(testString); 匹配多个模

java 自己实现字符串的匹配

package com.learn.algorithm.Str; /** * 自己实现 字符串的匹配 * @author Jiekun.Cui * */ public class SString { public static void main(String[] args) { System.out.println(indexOf("china","in",0)); } /** * 字符串匹配算法 -- 查找s2 在s1 中的位置 * @param s1 * @p

字符串的匹配

字符串的匹配 时间限制: 1 Sec  内存限制: 128 MB 题目描述 相信大家都做许多的字符串匹配问题了,一天,503集训室的俊哥突然想出了新点子.现在给你两个字符串a,b求最长公共子串.对于是字符串匹配大师的你来说,这个再简单不过了.但是,如果现在你有k次修改机会,每次你都可以选择其中某个串的某个位置.将其修改成任意字符. 你需要合理使用这k次修改机会,使得修改后字符串的最长公共子串最长.相信这个对于你来说也很简单. 输入 题目中有多组数据,每组数据的第一行为一个整数k.表示修改次数.

awk使用正则精确匹配

[[email protected] home]# cat file 5001][YRSD5-1][YRSD5-1-2][0203008400028411] 010102 5001][YRSD7-1][YRSD7-1-2][0203008400028411] 010102 5001][YRSD5-1][YRSD5-1-20][14030084000286E7] 010101 5001][YRSD7-1][YRSD7-1-3][03030084000285C0] 010102 5001][YRSD

三思考,实现自己定义404页:Tomcat、SpringMVC精确匹配、重写DispatchServlet

第1种方式:Tomcat直接处理 web.xml <error-page> <error-code>404</error-code> <location>/error/404.htm</location> </error-page> 这样的仅仅能展示纯静态的页面,很不灵活. 第2种方式:利用Spring MVC的最精确匹配 @Controller public class UrlNotFoundController { @Reques

C++实现的字符串模糊匹配

C++基本没有正则表达式功能,当然像Boost里提供了正则.本文来源于博客园园友的一篇文章,请看: C/C++ 字符串模糊匹配 很早之前就看过这篇文章,原作者的需求很明确.代码实现也很好. 之所以又写这篇文章,是因为原作者只介绍了在Linux系统下直接调用系统函数fnmatch即可实现,而没有考虑在Windows在的使用. 本人这周看了下Google-glog代码,恰巧发现了一个类似fnmatch的简单实现,因此综合起来提供了一个跨平台的接口. 直接拿原作者的需求为例(再次感谢原作者大熊先生,我

java.sql.SQLException:ORA-01861:文字和格式字符串不匹配

1.错误描述 java.sql.SQLException:ORA-01861:文字和格式字符串不匹配 2.错误原因 字段名为statis_date在数据库中存储的数据类型是Date,而在Java中拼接SQL语句时传参数却是字符串类型,类型不匹配,导致出错 3.解决办法 (1)修改数据库中该字段的数据类型 这种方法不太建议 (2)修改拼接时传参数方式,将参数利用to_date转换