字符串匹配算法(四)可以滑动多远

Rabin-Karp算法字符串匹配问题 为什么写这篇博客 其实有不少博客都有写Rabin-Karp算法,而且这个算法也非常简单易懂,但是很人都说“该算法的理论复杂度是O(mn),在实际生活中是O(m+n)”。 其实这个是不对的,在理论上,这个算法的复杂度也是O(m+n)。这篇文章就是想更深的一步讨论Rabin-Karp算法,解释为什么它的复杂度就应该是O(m+n)。 SubString Pattern Matching(字... 阅读详情
 记得在穷举法中,每一趟比较后,无论成与不成,都将模式向右滑动一个位置,然后继续比较。有没有办法能利用之前的比较结果,使得模式滑动的更远一点呢?

在介绍经典的KMP算法前,我先介绍几个简单的滑动类算法。

Not So Naive
同名字一样,这个算法的确有点幼稚,它根据模式的前两个字符是否相同来滑动比穷举法稍长一点的距离:如果前两个字符相同,那么文本中与第二个字符不同则必然也与第一个不同;如果前两个字符不同,则与第二个相同的文本字符必然与第一个不同。

那么这两种情况下不用比较都可以断定,文本字符与模式的第一个字符肯定不相同,于是能比穷举法多滑动1个位置。

代码见下:
  1. void NSN(char *x, int m, char *y, int n) {
  2.    int j, k, ell;
  3.   
  4.    /* Preprocessing */
  5.    if (x[0] == x[1]) {
  6.       k = 2;
  7.       ell = 1;
  8.    }
  9.    else {
  10.       k = 1;
  11.       ell = 2;
  12.    }
  13.   
  14.    /* Searching */
  15.    j = 0;
  16.    while (j <= n - m)
  17.       if (x[1] != y[j + 1])
  18.          j += k;
  19.       else {
  20.          if (memcmp(x + 2, y + j + 2, m - 2) == 0 &
  21.              x[0] == y[j])
  22.             OUTPUT(j);
  23.          j += ell;
  24.       }
  25. }
这个算法仅需要常数时间和空间的预处理,比较过程中,先比较模式第二个字符,然后比较其余位置,为的就在某些情况下省掉第一个字符的比较,达到滑动的目的。不过复杂度依然是O(mn)的,比起穷举法或者有轻微改善吧。

想法的确够幼稚,仅仅只考虑了两个模式字符,滑动的步子也太小,能否考虑的更多一点呢?下面请看Quick Search算法。

Quick Search
见到这个名字,不禁让人想起快速排序了,快速排序在最坏情况下是n平方的复杂度,而通常情况下速度超级快,Quick Search莫非也是这样的?没错,就是这样,这个算法在模式长度短而字母表大时,有着优异的表现,尽管它的搜索时间复杂度是O(mn)。

算法的思想是这样,如果文本中某个字符根本就没在模式中出现过,那么就不需要再去和模式中的任何一个比较;如果该字符出现过,那么为了不漏掉可能的匹配,只好与最晚出现过的位置对齐进行比较了。

代码如下:
  1. void preQsBc(char *x, int m, int qsBc[]) {
  2.    int i;
  3.    for (i = 0; i < ASIZE; ++i)
  4.       qsBc[i] = m + 1;
  5.    for (i = 0; i < m; ++i)
  6.       qsBc[x[i]] = m - i;
  7. }
  8. void QS(char *x, int m, char *y, int n) {
  9.    int j, qsBc[ASIZE];
  10.    /* Preprocessing */
  11.    preQsBc(x, m, qsBc);
  12.  
  13.    /* Searching */
  14.    j = 0;
  15.    while (j <= n - m) {
  16.       if (memcmp(x, y + j, m) == 0)
  17.          OUTPUT(j);
  18.       j += qsBc[y[j + m]];               /* shift */
  19.    }
  20. }
理解这个算法,请看22行,无论这一趟比较是否成功,都进行模式串的滑动,这个滑动就是根据窗口之外的第一个字符位于模式串的位置来决定的,你可以把窗口外第一个字符是否能匹配看成下一趟比较的前提。

现在你知道为何这个算法最适合在短模式和大字母表下运行了,因为字母表大,模式短,则文本字符不在模式中出现的几率就大,因此更大可能性得进行最长距离的滑动,而且模式短,花在比较上的时间就短,可以尽量多滑动。

美中不足的是这个算法最坏情况下复杂度还是O(mn),尽管预处理中已经利用上了每一个模式字符了。通过滑动能找到一个线性算法吗?仔细审视一下比较过程,造成算法非线性的根本原因是什么?没错,文本串回溯了。让我们来看看一个真正的线性算法——MP,以及它的改进——KMP。

MP/KMP
本着文本串不回溯的目标,MP算法横空出世,它的一个重要指导思想是,凡是比较过,被认定为相同的文本字符,绝不再拿出来比。道理上也是能说得通的,因为既然和模式串一部分相同,那么它的信息就已经存在于模式串中了。预处理时,模式串自己和自己的一部分进行比较,存储下自身的相似信息——Next数组。

以后在比较时,如果某处失配了,根据之前预处理的结果,可以直接滑动到自身相似的那一部分与文本串对齐,然后从失配处继续比较,避免了文本串回溯。

伟大的计算机科学家Knuth,就是写TAOUP的那位,对MP算法进行了些许修正,加上了自己的名字,成了KMP。Knuth注意到,如果滑动前的那个模式字符与滑动后的模式字符相同的话,那么再比较必然再次失配,导致又一次滑动,与其多级滑动,不如一滑到底。

代码:
  1. void preMp(char *x, int m, int Next[]) {
  2.    int i, j;
  3.    i = 0;
  4.    j = Next[0] = -1;
  5.    while (i < m) {
  6.       while (j > -1 && x[i] != x[j])
  7.          j = Next[j];
  8.       i++;
  9.       j++;
  10.       // 下面注掉的三行去掉注释就成KMP了
  11.       //if (x[i] == x[j])
  12.       //   Next[i] = Next[j];
  13.       //else
  14.          Next[i] = j;
  15.    }
  16. }
  17. void MP(char *x, int m, char *y, int n) {
  18.    int i, j, Next[XSIZE];
  19.    /* Preprocessing */
  20.    preMp(x, m, Next);
  21.    /* Searching */
  22.    i = j = 0;
  23.    while (j < n) {
  24.       while (i > -1 && x[i] != y[j])
  25.          i = Next[i];
  26.       i++;
  27.       j++;
  28.       if (i >= m) {
  29.          OUTPUT(j - i);
  30.          i = Next[i];
  31.       }
  32.    }
  33. }
MP和KMP算法都达到了O(m)的预处理时间和空间,O(n+m)的比较时间,算法实现是如此简单优美,算法思想是如此无可挑剔,还能滑的更远吗?我们拭目以待。
浅谈字符串匹配算法 —— BM算法 概述 BF算法在某些极端情况下,性能会退化的比较严重。 RK 算法需要用到哈希算法,设计一个可以应对各种类型字符的哈希算法则并不简单。 BM算法 BM(Boyer-Moore)算法是一种非常高效的字符串匹配算法,性能约是著名的KMP 算法的 3 到 4 倍。 但是BM算法的实现原理也很复杂。 BM算法的思想 我们把模式串和主串的匹配过程,可以看作模式串在主串中不停地往后滑... 阅读详情

相关推荐

阿里云Ubuntu部署Steam饥荒联机版服务器:从零到人联机的完整指南

本文详细介绍了在阿里云Ubuntu系统上部署Steam饥荒联机版服务器的完整流程,包括环境准备、SteamCMD安装、服务端配置、Mod管理及后台运行技巧。通过2核4GB的ECS实例配置和端口设置,实现5人流畅联机体验,适合游戏爱好者快速搭建专属服务器。

weixin_29229261的博客 986

用Python实现字符串滑动匹配(KMP)算法

关于滑动匹配算法,在网上有很解释,图、文、视频都有,不明白的可以自行百度。 在此我们用Python实现以下这个算法滑动匹配算法的精髓在于其不倒退性,即在主字符串上的临时匹配指针不会因为有任何情况导致回退,因此这个算法的时间复杂度在O(n)级别,在最不理想的情况下会达到O(m*n),其中m代表子字符串长度级别,n代表主字符串长度级别。 class KMPstr: farther_...

学习日常 577

滑动窗口算法字符串匹配中的巧妙应用

字符串匹配是计算机科学的基础问题之一,广泛应用于搜索引擎关键词提取、生物信息学基因序列分析、文本编辑器查找功能等场景。传统暴力匹配算法虽简单但效率低下,而滑动窗口算法通过“动态窗口”的设计,能在单次遍历中完成匹配,大幅提升性能。本文聚焦滑动窗口在字符串匹配中的核心逻辑,覆盖从基础概念到实战应用的完整知识链。本文将按“概念引入→原理拆解→代码实战→场景应用”的逻辑展开:先用超市扫码案例类比滑动窗口;再拆解窗口的“扩展-收缩”核心操作;接着通过3个LeetCode经典题演示具体实现;

AI 算法实战派 882

C++ 必刷题

必刷题 文章目录必刷题滑动窗口字符串匹配前缀树背包问题01背包问题完全背包问题动态规划系列爬火山类型最长递增序列[不同路径 II](https://leetcode-cn.com/problems/unique-paths-ii/)解码方法最大连续子序列编辑距离 滑动窗口 #include<iostream> using namespace std; const int N = 1000010; //队列q中装的是下标【重点】 int a[N], q[N], hh = 0, tt = -1;

LivingMu的博客 738

基本数据结构---滑动窗口

滑动窗口前言一、应用场景二、模板三、实践76. 最小覆盖子串567. 字符串的排列438. 找到字符串中所有字母异位词3. 无重复字符的最长子串总结 前言 滑动窗口属于双指针技巧的其中一种,两外两种分别是左右指针和快慢指针。其基本思想是维护一个窗口,不断滑动,更新数据,找到满足题意的答案。 一、应用场景 滑动窗口常用来解决字符串匹配问题。 匹配问题套路:不满足题意,右移窗口,更新数据;满足题意,左移窗口,更新数据。 其他情况需要具体问题,具体分析,如3.无重复字符的最长字串。 二、模板 public St

weixin_44484668的博客 1868

关于滑动窗口解决子串问题

目录 滑窗思想: 滑窗编程范式: 力扣76:最小覆盖子串 力扣438:找字符串中所有异位词 力扣3:无重复最长子串: 滑窗思想: 在解决字符串子串问题时,可以采用滑窗的思想; 1,在字符串S中使用双指针中左右指针技巧,初始化left = right = 0,把索引[left,right]成为一个窗口 2,不断增加right指针扩大窗口[left,right],直到窗口中字符...

WSTONECH的博客 582

字符串匹配算法(BM)

文章目录1. BM(Boyer-Moore)算法 1. BM(Boyer-Moore)算法 思想:有模式串中不存在的字符,那么肯定不匹配,往后移动几位,提高效率 BM原理:坏字符规则,好后缀规则 ...

Michael是个半路程序员 3万+

字符串匹配算法少?

文章目录BF算法RK算法编辑器中的全局替换方法:BM算法坏字符好后缀规则代码实现KMP算法 一说到字符串匹配算法,不知道会有少小伙伴不由自主的想起那个kmp算法呢? 想到是很正常的,谁让它那么优秀呢。 BF算法 不要被事物的表面现象所迷惑,这个算法全称:Brute Force,有个拉风的中文名:暴力匹配算法。 能想明白了吧。 如果模式串长度为 m,主串长度为 n,那在主串中,就会有 n-m+1 个长度为 m 的子串,我们只需要暴力地对比这 n-m+1 个子串与模式串,就可以找出主串与模式串匹配的子串。.

看,未来的博客 6780

算法案例分析—字符串模式匹配算法

目录 一、朴素的模式匹配算法 二、KMP算法(改进的模式匹配算法) hello!大家好哇,我是灰小猿,一个超会写bug的沙雕程序猿! 今天来和大家分享一个关于字符串比较的模式匹配算法,在数据结构中对字符串的相关操作中,对子串的定位操作通常称为串的模式匹配,同样他也是各种串处理中最重要的操作之一,同时子串也称为模式串,关于主串和模式串的匹配算法常用的主要有两种:朴素的模式匹配算法和KMP算法(改进的模式匹配算法),接下来将分别对这两种算法进行分析。 一、朴素的模式匹配算法 朴素的模式匹配算法也被称

累计发表博客60余万字,CSDN 博客专家、Java 领域优质创作者、华为云享专家、阿里云专家博主。专注分享 Java 优质文章,毕设实战项目开发,全网粉丝10W+ 7444

字符串匹配算法

坏字符的位置越靠右,下一轮模式串的挪动跨度越大,节省的比较次数也就越。这就是BM算法从右向左检测的好处。

qq_66478305的博客 3043

字符串匹配(BP&KMP算法

本文是基于懒猫老师的课程----BP&KMP所写,在观看本文之前最好配合视频或者PPT食用更佳

2402_88307286的博客 875

字符串相似度算法和最大公共子串提取算法

字符串相似度算法和最大公共子串提取算法 1. Levenshtein Distance 该算法又称之为 "编辑距离",用于计算两个字符串的相似程度。原理很简单,就是返回两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。次数越少,意味着字符串相似度越高。 例如将 kitten 转换成 sittin

sata1的专栏 1629

滑动窗口通用思想解决子串问题(438. 找到字符串中所有字母异位词)

https://leetcode-cn.com/problems/find-all-anagrams-in-a-string/solution/hua-dong-chuang-kou-tong-yong-si-xiang-jie-jue-zi-/ 本文详解「滑动窗口」这种高级双指针技巧的算法框架,带你秒杀几道难度较大的子字符串匹配问题: 76. 最小覆盖子串 438. 找到字符串中所有字母异位词 ...

qq_32534441的博客 1492

"求两个字符串的最长公共子串"(python)

题目描述:找出两个字符串的最长公共子串。例如:‘abccade’与字符串'dgcadde'的最长公共子串为'cad'. 暴力解法就不写了,方法一:动态规划: def getMaxSubStr(str1, str2): len1 = len(str1) len2 = len(str2) sb = '' maxs = 0 # 用来记录最长公共子串的长度 ...

LeoLee 5485

数据结构学习笔记--串的模式匹配

广西无盘 MC SYSTEM 3 655 2007-09-26T12:33:00Z 2007-09-26T12:34:00Z 1 629 3589 Http://www.gxwp.net 29 8 4210 11.5606 Clean Clean

timercrack的专栏 1912

字符串匹配算法(一)简介

注:本文大致翻译自EXACT STRING MATCHING ALGORITHMS,去掉一些废话,增加一些解释。文本信息可以说是迄今为止最主要的一种信息交换手段,而作为文本处理中的一个重要领域——字符串匹配,就是我们今天要说的话题。(原文还特意提及文本数据数量每18个月翻一番,以此论证算法必须要是高效的。不过我注意到摩尔定律也是18个月翻番,这正说明数据的增长是紧紧跟随处理速度的,因此越是使用高效

oyd的专栏 6924

字符串匹配算法(三)位运算的魔法——KR与SO

位运算经常能做出一些不可思议的事情来,例如不用临时变量要交换两个数该怎么做呢?一个没接触过这类问题的人打死他也想不出来。如果拿围棋来做比喻,那么位运算可以喻为编程中的“手筋”。按位的存储方式能提供最大的存储空间利用率,而随着空间被压缩的同时,由于CPU硬件的直接支持,速度竟然神奇般的提升了。举个例子,普通的数组要实现移位操作,那是O(n)的时间复杂度,而如果用位运算中的移位,就是一个指令搞定了。K

oyd的专栏 3136

Java简单实现滑动窗口

由于最近有一个统计单位时间内某key的访问次数的需求,譬如每5秒访问了redis的某key超过100次,就取出该key单独处理。 这样的单位时间统计,很明显我们都知道有个边界问题,譬如5秒内100次的限制。刚好前4.99秒访问都是0,最后0.01秒来了100次,5.01秒又来了100次。也就是访问有明显的毛刺情况出现,为了弱化这个毛刺情况,我们可以采用滑动窗口。 滑动窗口 滑动窗口的主要原理...

tianyaleixiaowu的专栏 1万+

LightGBM之LGBMRegressor()参数详解以及调参

LightGBMLight Gradient Boosting Machine)是一种梯度提升框架,它使用决策树作为基学习器。LightGBM 可以说是在 XGBoost 上做的优化。LightGBM 为高效并行计算而生,它的 Light 体现在以下几个点上:更快的训练速度更低的内存使用支持单机线程,机并行计算,以及 GPU 训练能够处理大规模数据。

我走的每一步都算数 3712

(全新整理)2006-2022年农民专业合作社数量 30个省面板数据

1、资源内容地址:https://blog.csdn.net/2301_79696294/article/details/1440168202、数据特点:今年全新,手工精心整理,放心引用,数据来自权威,且标注《数据来源》,相对于其他人的控制变量数据准确很,适合写论文做实证用 ,不会出现数据造假问题3、适用对象:大学生,本科生,研究生小白可用,容易上手!!!4、课程引用: 经济学,地理学,城市规划与城市研究,公共政策与管理,社会学,商业与管理

上一篇: 字符串匹配算法(三)位运算的魔法——KR与SO
下一篇: 围棋AI之路(一)理论
oyd
oyd
博客等级 码龄24年 186粉丝 81原创
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值