看毛片(KMP)算法简析

看毛片算法又称KMP算法。该算法之所以得名无外乎如下原因。

每当涉及该算法都甚新鲜,极想把玩一番,经过一番琢磨,终于悟透其本质。遂将其束之高阁,数月之后,再相邂逅,新鲜如初,又是一番把玩、醒悟、遗忘,如此循环以至无穷。足见,该算法与看毛片的道理一脉相承。初看新鲜刺激,观摩研究,醒悟不过如此而已。遂撇下而顾其它,数月之后,复习之,依然新鲜激动如故。以致数年。

KMP算法核心在于求匹配失败时模式串的后退数组,大多数都命名为next数组,感觉pre应该更符合直觉。假设在T[i] 和P[j]处失配,j必须是往回退的不可能在向前走。因此要求的后退数组应该这个样子:pre[sizeof(P)]

(1)

T[i] 和P[j]处失配,则找到pre[j],假设pre[j]=k,意味着P有相同的前缀和后缀,且长度为k,此时在j处失配,自然要回退,退到哪?退到k处。

(2)

咋求pre[j+1]呢?要分两种情况,

a) pre[j]=pre[k], 所以pre[j+1]=k+1=pre[j]+1,中间那个k+1难理解?要知道k是什么意思,k是P[0..j]的相同前缀和后缀长度,此时两个缀的后面各增加了一个相同的字符,所以pre[j+1]自然要在k的基础上+1了;

b)
pre[j]!=pre[k],这就意味着pre[j+1]的相同前缀和后缀不能用pre[j]那一套了。此时,要有递归的思想了,要观察更早的前缀和后缀是否能满足pre[j]=pre[k],如果找到这个位置则可基于此求出pre[j+1]了。如果一直往前看,一直没发现满足要求的前缀和后缀,咋整?不咋整,说明P[0..j+1]不存在相同的前缀和后缀,此时如果T[i+1]和P[j+1]失配了,P就只能从头开始了。找不到在代码中这样表示pre[0]=-1。

上面基本就是看毛片算法的精髓。还是结合代码来理解吧。程序不会看会的,得写!

    int kmp(char *t, char *p) {
         int tsize = strlen(t), psize = strlen(p), k=-1, j=0, i=0, *prev = new int[psize];
         prev[0] = -1;

         while (j < psize-1)
            if ( k == -1 || p[k] == p[j] ) prev[++j] = ++k;
            else k = prev[k];

         i = j =0;
         while (i < tsize && j < psize)
            if (j == -1 || t[i] == p[j]) {i++;j++;}
            else j = prev[j]; 

        if (j == psize) return i - j;
        else  return -1;
      }

求后退数组加模式匹配,世界上基本不会有比这更短的KMP了!

时间: 2024-09-30 14:36:42

看毛片(KMP)算法简析的相关文章

linux网络流控-htb算法简析

项目中用tc,htb做流控期间,研究了htb(分层令牌桶)算法的实现.觉得这种思想在类似与有消费优先级的生产者消费者场景中也很适用.该算法过于复杂,碍于嘴拙遂在标题中加了简析,只介绍核心思想和关键代码的实现. 一个栗子: tc qdisc add dev eth0 root handle 1: htb tc class add dev eth0 parent 1: classid 1:1 htb rate 100mibps tc class add dev eth0 parent 1:1 cla

JAVA里的CAS算法简析

Atomic 从JDK5开始, java.util.concurrent包里提供了很多面向并发编程的类. 使用这些类在多核CPU的机器上会有比较好的性能.主要原因是这些类里面大多使用(失败-重试方式的)乐观锁而不是synchronized方式的悲观锁. 跟踪了一下AtomicInteger的incrementAndGet的实现.仅做个笔记, 方便以后再深入研究. 1. incrementAndGet的实现 public final int incrementAndGet() { for (;;)

KMP算法 学习笔记

kmp算法在很多人看来是如此的厉害,很早之前就学过了,但是各种看不懂把我拦住了,现在重新拾取,来写一下个人的学习总结. kmp看毛片算法(小甲鱼教的)(在这给小甲鱼做个广告,我个人看来小甲鱼讲的数据结构很好,很有趣.个人创业不容易,希望大家多多支持www.fishc.com小甲鱼,我跟小甲鱼素不相识,只是有用的东西大家分享) 好了言归正传. 如果你之前看过kmp算法没有看懂希望在这不要带着一种恐惧感,如果你没看过那是更好. 网上有很多详细教程,但是大部分都很啰嗦,容易把人看晕. kmp算法没有什

KMP算法的一次理解

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

kmp//呵呵!看毛片算法

以前刚学的时候迷迷糊糊的,一看就懵圈,前几天捡起来的时候 发现还不会 于是研究了两天,自尊心严重受挫,今天的时候  突然一道灵光迸发,居然 感觉好像懂了,于是又琢磨起来  终于  我懂了  呵呵!   0 1 2 3 4 5 6 7 8 9 主串   : a b c d  e a b c d  f         i 0 1 2 3 4 5 6 7 8 9 模式串:         c d f j i=4时 e!=f匹配失败  传统字符匹配是让i=3,j=0继续匹配,i++,j=0. 此种匹配方

从有限状态机的角度去理解Knuth-Morris-Pratt Algorithm(又叫KMP算法,”看毛片“算法)

转载请加上:http://www.cnblogs.com/courtier/p/4273193.html 在开始讲这个文章前的唠叨话: 1:首先,在阅读此篇文章之前,你至少要了解过,什么是有限状态机,什么是KMP算法,因为,本文是从KMP的源头,有限状态 机来讲起的,因为,KMP就是DFA(Deterministic Finite Automaton)上简化的. 2:很多KMP的文章(有限自动机去解释的很少),写得在我看来不够好,你如果,没有良好的数学基础就很难去理解他们(比如下图), 因为,你

常用排序算法时间复杂度和空间复杂度简析

1. preface /**** *    This article will try to explain something about: *        --Bubble sort. *        --Quick sort. *        --Merge sort. *        --Heap sort. *    To read this, some prerequisites is necessary: *        --a survive skill in C pr

看数据结构写代码(18) KMP算法

求 子串 的 位置 有两种方法,一种是暴力搜索法,另一种就是KMP 算法.他们的效率 在一般的情况下,区别不大.但是在 串的 变化 范围特别小的情况下,例如 只有 0 和 1,KMP 的时间复杂度是 O(m+n),而暴力搜索法定时间 复杂度 是 O(m*n),(m,n分别指 子串 和 母串的 长度) 下面给出两种算法的代码 欢迎指出代码不足 // Kmp2.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <stdlib.h

通过图片对比带给你不一样的KMP算法体验

KMP 算法,俗称“看毛片”算法,是字符串匹配中的很强大的一个算法,不过,对于初学者来说,要弄懂它确实不易. 笔者认为,KMP 算法之所以难懂,很大一部分原因是很多实现的方法在一些细节的差异.体现在几个方面: next 数组,有的叫做“失配函数”,其实是一个东西: next 数组中,有的是以下标为 0 开始的,有的是以 1 开始的: KMP 主算法中,当发生失配时,取的 next 数组的值也不一样!就这样,各说各的,乱的很! 所以,在阐述我的理解之前,我有必要说明一下,我是用 next 数组的,