字符串匹配暴力算法 与 字符串匹配的KMP算法

声明:先看一下阮一峰的网络日志关于字符串的KMP算法的讲解。本文图片均引用于这篇日志。

在先前的笔试中遇到了关于字符串匹配的问题,一时脑袋卡壳没写好算法。现在就来分析分析

暴力算法和KMP算法各自原理,以及代码实现之间差异,并且总结一下好算法的一般思路

===========================================================================

各自原理:

暴力算法:

1.

我们把长的字符串做为一个文本字符串,命名为strText,把短的字符串称为目标串,命名为strTarget。

文本串"BBC ABCDAB ABCDABCDABDE"的第一个字符‘B’与目标串"ABCDABD"的第一个字符‘A’

比较不产生匹配,在整个过程中,我们假设红色虚线是固定的。因此,文本串向左边移动一个字符。

2.

字符‘B’与‘A’不产生匹配,文本串继续左移。

3.

直到这里,此时出现第一个匹配,程序中将文本串和目标串都向左移动,并且记录下此时文本串出来比较

的那个元素(就是字符‘A’)的位置。

4.

继续比较,又是一个匹配,继续移动。

5.

此时出现不匹配,比较重新归位,根据前面记录的‘A’的位置文本串进入下一个字符‘B’,而目标串的下标重新开始,

继续比较。

6.

这个就是暴力算法的大致原理分析过程。

KMP算法:

7.

一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是"ABCDAB"。KMP算法的想法是,设法利用这个已知信息,

不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。

8.

怎么做到这一点呢?可以针对目标串,算出一张《部分匹配表》(Partial Match Table)。这张表是如何产生的,后面再介绍,

这里只要会用就可以了。

9.

已知空格与D不匹配时,前面六个字符"ABCDAB"是匹配的。查表可知,最后一个匹配字符B对应的"部分匹配值"为2,因此按照

下面的公式算出向后移动的位数:

移动位数 = 已匹配的字符数 - 对应的部分匹配值

6 - 2 = 4;所以移动 4 个字符。

10.

移动后就来到了这里,空格与字符‘C’不匹配,再次利用《部分匹配表》查询移动位数。2 - 0 = 2;因此移动2个字符。

11.

再次移动后来到了这里,空格与字符‘A’不匹配,再次利用《部分匹配表》查询移动位数。1 - 0 = 1;因此移动1个字符。

12.

一一对比完后到了D字符,发现文本串的字符‘C’与目标串字符‘D’不匹配,查询移动位数。6 - 2 = 4;因此移动4个字符。

13.

移动后就来到这了,一一比较完后发现全部匹配。目标串匹配成功!

14.

关于《部分匹配表》

下面介绍《部分匹配表》是如何产生的。

首先,要了解两个概念:"前缀"和"后缀"。

"前缀"指除了最后一个字符以外,一个字符串的全部头部组合;

"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。如上图所示。

15.

"部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。以"ABCDABD"为例,

16.

"部分匹配"的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么它的"部分匹配值"就是2("AB"的长度)。

搜索词移动的时候,第一个"AB"向后移动4位(字符串长度-部分匹配值),就可以来到第二个"AB"的位置。

分析了这么详细,正如那句话,Talk is cheap, show me the code.来写一写代码吧!

代码实现:

暴力算法:

void
SViolence( const char strText[ ], const char strSearch[ ] )
{
    int lengthOfstrText, lengthOfstrSearch;
    int i, j, ii;

    lengthOfstrText = strlen( strText );
    lengthOfstrSearch = strlen( strSearch );

    /*for( i = 0, j = 0, ii = 0; i < lengthOfstrText && j < lengthOfstrSearch; )*/
    for( i = 0, j = 0, ii = 0; j < lengthOfstrSearch; )
    {
        if( strText[ i ] == strSearch[ j ] )
        {
            j++;
            i++;
            continue;

        }
        else
        {
            i = ii;
            i++;
            ii = i;
            j = 0;/* make a clear */
            continue;
        }
    }

    if( j == lengthOfstrSearch )
        printf( "Existence!" );
    else
        printf( "No Existence!" );
}

在程序中的ii变量就是记录位置的。理解这个算法的运行过程可以很清楚的知道在算法中做了很多重复的比较工作。

时间复杂度分析:咋一看这个程序感觉很(hen)快(man)啊,只有一个for循环而已嘛。呵呵,其实你有所不知,这个for循环与众不同,它的结束不只是依赖于for循环条件而已,而是有循环条件和循环体的i,j,ii,等变量共同决定的。我们记lengthOfText = m,lengthOfSearch = n;所以这个算法的时间复杂度大概为:T(
n )= O( m * n )这个级别已经是我们所唾弃的了。

KMP算法:

时间: 2024-10-14 13:05:42

字符串匹配暴力算法 与 字符串匹配的KMP算法的相关文章

数据结构与算法JavaScript (五) 串(经典KMP算法)

数据结构与算法JavaScript (五) 串(经典KMP算法) KMP算法和BM算法 KMP是前缀匹配和BM后缀匹配的经典算法,看得出来前缀匹配和后缀匹配的区别就仅仅在于比较的顺序不同 前缀匹配是指:模式串和母串的比较从左到右,模式串的移动也是从 左到右 后缀匹配是指:模式串和母串的的比较从右到左,模式串的移动从左到右. 通过上一章显而易见BF算法也是属于前缀的算法,不过就非常霸蛮的逐个匹配的效率自然不用提了O(mn),网上蛋疼的KMP是讲解很多,基本都是走的高大上路线看的你也是一头雾水,我试

串匹配模式中的BF算法和KMP算法

考研的专业课以及找工作的笔试题,对于串匹配模式都会有一定的考察,写这篇博客的目的在于进行知识的回顾与复习,方便遇见类似的题目不会纠结太多. 传统的BF算法 传统算法讲的是串与串依次一对一的比较,举例设目标串S="ababcabcacb",模式串T="abcac",利用BF算法这个过程就会表示为: 将S串理解为数组,底标从0开始,即从a开始,第一次匹配过程如下: ok,当发现T串尚未匹配结束,就开始出现了错误,S串坐标右移+1,开始从b匹配,过程如下: 出现不同,继续

KMP算法详解 --- 彻头彻尾理解KMP算法

[经典算法]——KMP,深入讲解next数组的求解 前言 之前对kmp算法虽然了解它的原理,即求出P0···Pi的最大相同前后缀长度k:但是问题在于如何求出这个最大前后缀长度呢?我觉得网上很多帖子都说的不是很清楚,总感觉没有把那层纸戳破,后来翻看算法导论,32章 字符串匹配虽然讲到了对前后缀计算的正确性,但是大量的推理证明不大好理解,没有与程序结合起来讲.今天我在这里讲一讲我的一些理解,希望大家多多指教,如果有不清楚的或错误的请给我留言. 1.kmp算法的原理: 本部分内容转自:http://w

字符串匹配KMP算法的理解(详细)

1. 引言 本KMP原文最初写于2年多前的2011年12月,因当时初次接触KMP,思路混乱导致写也写得混乱.所以一直想找机会重新写下KMP,但苦于一直以来对KMP的理解始终不够,故才迟迟没有修改本文. 然近期因开了个算法班,班上专门讲解数据结构.面试.算法,才再次仔细回顾了这个KMP,在综合了一些网友的理解.以及算法班的两位讲师朋友曹博.邹博的理解之后,写了9张PPT,发在微博上.随后,一不做二不休,索性将PPT上的内容整理到了本文之中(后来文章越写越完整,所含内容早已不再是九张PPT 那样简单

模式字符串匹配问题(KMP算法)

这两天又看了一遍<算法导论>上面的字符串匹配那一节,下面是实现的几个程序,可能有错误,仅供参考和交流. 关于详细的讲解,网上有很多,大多数算法及数据结构书中都应该有涉及,由于时间限制,在这就不重复了. 需要说明的是: stra:主串,及需要从中寻找模式串的字符串 strb:模式串 <算法导论>上面包括严蔚敏老师<数据结构>,字符串下表是按从1开始,并且<数据结构>一书中貌似吧字符串的第一个字符用来储存字符串长度.这里我改成了0. maxlen :字符串的最长

从暴力匹配到KMP算法

前言 现在有两个字符串:\(s1\)和\(s2\),现在要你输出\(s2\)在\(s1\)当中每一次出现的位置,你会怎么做? 暴力匹配算法 基本思路 用两个指针分别指向当前匹配到的位置,并对当前状态进行分类讨论:若相同则继续往下匹配,否则回溯 大致思路 用\(i\)来存储\(s1\)当前匹配到的位置,用\(j\)来存储\(s2\)当前匹配到的位置,则可得初始状态下\(i=j=0\). 对于当前状态,有两种可能性: ①:\(s1[i]==s2[j]\).则\(i++,j++\) ②:\(s1[i]

[转July]KMP算法(mark)

从头到尾彻底理解KMP 作者:July时间:最初写于2011年12月,2014年7月21日晚10点 全部删除重写成此文,随后的半个多月不断反复改进. 1. 引言 本KMP原文最初写于2年多前的2011年12月,因当时初次接触KMP,思路混乱导致写也写得混乱.所以一直想找机会重新写下KMP,但苦于一直以来对KMP的理解始终不够,故才迟迟没有修改本文. 然近期因在北京开了个算法班,专门讲解数据结构.面试.算法,才再次仔细回顾了这个KMP,在综合了一些网友的理解.以及跟我一起讲算法的两位讲师朋友曹博.

KMP算法的一次理解

1. 引言 在一个大的字符串中对一个小的子串进行定位称为字符串的模式匹配,这应该算是字符串中最重要的一个操作之一了.KMP本身不复杂,但网上绝大部分的文章把它讲混乱了.下面,咱们从暴力匹配算法讲起,随后阐述KMP的流程步骤.next 数组的简单求解.递推原理.代码求解,接着基于next 数组匹配,谈到有限状态自动机,next 数组的优化,KMP的时间复杂度分析,最后简要介绍两个KMP的扩展算法. 2. 暴力匹配算法 2.1 问题描述: 有一个文本串s和一个模式串p,现在要查找p在s中的位置,怎么

关于KMP算法的认识

目前大二,大一时年自己纯属划水度过,身为一个学计算机的可能连一些没学的还要差.感觉自己不能在这样颓废下去了,是时候要努力一波了. 决定开始从算法开始补起. 大一数据结构在字符串匹配的时候曾讲过,当时对计算机还处于相当懵逼的状态,自然也就不会.前几天看算法题又一次看到了,决定把它补回来. KMP算法 首先要先看 BF算法--最简单直观的模式匹配算法 如果用BF暴力匹配的思路 算法步骤: 分别利用计数指针i , j  指示主串S和模式T中当前正待比较的字符位置pos,j初值为0: 如果当前字符匹配成

什么是Kmp算法?

1. 前几天做了一道题,做错了,遂良心发现,我觉得你从头看到尾,差不多可以明白KMP算法的思想 2. 暴力匹配算法 假设现在我们面临这样一个问题:有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢? 如果用暴力匹配的思路,并假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置,则有: 如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符: 如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0.相当于每次匹