The key of Kmp is to build a look up table that records the match result of prefix and postfix. Value in the table means the max len of matching substring that exists in both prefix and postfix. In the prefix this substring should start from 0, while in the postfix this substring should ends at current index.

For example, now we have a string "ababc"

The KMP table will look liks this:

 a  b  a  b  c
-1 0 1 2

(Note: we will not match substring with itself, so we will skip index 0)

So how does this table help us search string match faster?

Well, the answer is if we are trying to match a char after posfix with target string and failed, then we can smartly shift the string, so that the matching string in perfix will replace postfix and now we can try to match the char after prefix with this char in target.

Take above string as an example.

Now we try to match string "ababc" with "abababc".

We will initially have match as below

 0 1 2 3 4 5 6
 a b a b a b c (string x)
a b a b c (string y)
-1 0 1 2

We found char at index 4 does not match, then we can use look up table and shift the string y wisely.

We found table[3] = 2, which means we can shift the string y rightward by 2, and still have same but shorter prefix before index 4, like this:

 0 1 2 3 4 5 6
a b a b a b c (string x)
a b a b c (string y)
-1 0 1 2

If there is a long gap between prefix and postfix, this shift can help us save a lot of time. In the brute force way, we cannot do that because we have no information of the string. We have to compare each possible pair of chars. While in KMP, we know the information of string y so we can move smartly. We can directly jump to the next possible match pairwhile discard useless pair of chars.

We are almost done with KMP, but we still have one special case that needs to be taken care of.

Say now we have a input like this:

 0 1 2 3 4 5
a a b a a a
-1 1 0 2 3

How should we build the KMP table for this string?

Say the pointer in prefix is 'x', which is at index 2 now and the pointer in postfix is 'y' which is at index 5 now. We need to match 'b' pointed by x with 'a' pointed by y. It is an unmatched pair, how should we update the cell?

Well, we really don't need to reset it to 0, that will make us skip a valid shorter matching substring "aa".

What we do now is just to shorten the length of substring by 1 unit and try to match a shorter substring "aa". This can be done by moving pointer x to the index recorded in [indexOf(x) - 1] while keep pointer y stay still. This is because by following the value in KMP table we can always make sure previous part of prefix and postfix is matched even we have shorten their length, so wo only need to care about the char after matched part in prefix and posfix.

Code: [Java]

// JAVA program for implementation of KMP pattern
// searching algorithm class KMP_String_Matching {
void KMPSearch(String pat, String txt)
{
int M = pat.length();
int N = txt.length(); // create lps[] that will hold the longest
// prefix suffix values for pattern
int lps[] = new int[M];
int j = 0; // index for pat[] // Preprocess the pattern (calculate lps[]
// array)
computeLPSArray(pat, M, lps); int i = 0; // index for txt[]
while (i < N) {
if (pat.charAt(j) == txt.charAt(i)) {
j++;
i++;
}
if (j == M) {
System.out.println("Found pattern "
+ "at index " + (i - j));
j = lps[j - 1];
} // mismatch after j matches
else if (i < N && pat.charAt(j) != txt.charAt(i)) {
// Do not match lps[0..lps[j-1]] characters,
// they will match anyway
if (j != 0)
j = lps[j - 1];
else
i = i + 1;
}
}
} void computeLPSArray(String pat, int M, int lps[])
{
// length of the previous longest prefix suffix
int len = 0;
int i = 1;
lps[0] = 0; // lps[0] is always 0 // the loop calculates lps[i] for i = 1 to M-1
while (i < M) {
if (pat.charAt(i) == pat.charAt(len)) {
len++;
lps[i] = len;
i++;
}
else // (pat[i] != pat[len])
{
// This is tricky. Consider the example.
// AAACAAAA and i = 7. The idea is similar
// to search step.
if (len != 0) {
len = lps[len - 1]; // Also, note that we do not increment
// i here
}
else // if (len == 0)
{
lps[i] = len;
i++;
}
}
}
} // Driver program to test above function
public static void main(String args[])
{
String txt = "ABABDABACDABABCABAB";
String pat = "ABABCABAB";
new KMP_String_Matching().KMPSearch(pat, txt);
}
}
// This code has been contributed by Amit Khandelwal.

  

Reference:

https://www.geeksforgeeks.org/java-program-for-kmp-algorithm-for-pattern-searching-2/

https://leetcode.com/problems/shortest-palindrome/discuss/60113/Clean-KMP-solution-with-super-detailed-explanation

KMP Demo的更多相关文章

  1. KMP算法实现

    链接:http://blog.csdn.net/joylnwang/article/details/6778316 KMP算法是一种很经典的字符串匹配算法,链接中的讲解已经是很明确得了,自己按照其讲解 ...

  2. kmp算法,求重复字符串

    public class Demo { public static void main(String[] args) { String s1 = "ADBCFHABESCACDABCDABC ...

  3. KMP 算法 & 字符串查找算法

    KMP算法 Knuth–Morris–Pratt algorithm 克努斯-莫里斯-普拉特 算法 algorithm kmp_search: input: an array of character ...

  4. 【数据结构&算法】10-串基础&KMP算法源码

    目录 前言 串的定义 串的比较 串的抽象类型数据 串与线性表的比较 串的数据 串的存储结构 串的顺序存储结构 串的链式存储结构 朴素的模式匹配算法 模式匹配的定义 朴素的匹配方法(BRUTE FORC ...

  5. 通过一个demo了解Redux

    TodoList小demo 效果展示 项目地址 (单向)数据流 数据流是我们的行为与响应的抽象:使用数据流能帮我们明确了行为对应的响应,这和react的状态可预测的思想是不谋而合的. 常见的数据流框架 ...

  6. KMP算法求解

    // KMP.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> using namespac ...

  7. 很多人很想知道怎么扫一扫二维码就能打开网站,就能添加联系人,就能链接wifi,今天说下这些格式,明天做个demo

    有些功能部分手机不能使用,网站,通讯录,wifi基本上每个手机都可以使用. 在看之前你可以扫一扫下面几个二维码先看看效果: 1.二维码生成 网址 (URL) 包含网址的 二维码生成 是大家平时最常接触 ...

  8. 在线浏览PDF之PDF.JS (附demo)

    平台之大势何人能挡? 带着你的Net飞奔吧!:http://www.cnblogs.com/dunitian/p/4822808.html#skill 下载地址:http://mozilla.gith ...

  9. 简单有效的kmp算法

    以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...

随机推荐

  1. Spring框架的IOC之注解方式的快速入门

    1. 步骤一:导入注解开发所有需要的jar包 * 引入IOC容器必须的6个jar包 * 多引入一个:Spring框架的AOP的jar包,spring-aop的jar包 2. 步骤二:创建对应的包结构, ...

  2. 学习类App原型制作分享-Wokabulary

    Wokabulary是一款多功能词汇学习App,可以学习多国语言词汇.原型的引导页面采用的图片+文字+分页器,需要注意的是分页器选中位置要与页面顺序一致.其次是语言的选择页面,在前面给大家介绍过滚动区 ...

  3. circos 绘制关系型图ribbon,并加入透明度

    luminance = lum80<<include colors_fonts_patterns.conf>><colors># r,g,b,a color def ...

  4. 内网IP和公网IP的区别

        内网IP和公网IP的区别     什么是内网IP: 一些小型企业或者学校,通常都是申请一个固定的IP地址,然后通过IP共享(IP Sharing),使用整个公司或学校的机器都能够访问互联网.而 ...

  5. 命名空间namespace ,以及重复定义的问题解析

    名字空间是用来划分冲突域的,把全局名字空间划分成几个小的名字空间.全局函数,全局变量,以及类的名字是在同一个全局名字空间中,有时为了防止命名冲突,会把这些名字放到不同的名字空间中去. 首先我们看一下名 ...

  6. Ehcache配置参数简介

    < defaultCache         maxElementsInMemory = "10000"         maxElementsOnDisk = " ...

  7. spring-data-jpa+hibernate 各种缓存的配置演示

    本文所有测试用代码在https://github.com/wwlleo0730/restjplat 的分支addDB上 目前在使用spring-data-jpa和hibernate4的时候,对于缓存关 ...

  8. 什么是DNS服务器

    DNS:是做域名解析的.我们平时所输入的网址,都是某台服务器的主机名,比如www.BAIDU.COM,主机之间通讯是通过IP地址访问的,这个是有需要某个机制,把地址解析成名字,因为IP地址是一串数字, ...

  9. js 验证input 输入框

    <h1>js验证输入框内容</h1><br /><br /> 只能输入英文<input type="text" onkeyup ...

  10. vivado用法

    声明为”DEBUG”,即使没有连接到其他模块,也不会被优化掉.但并不是所有的信号都是在声明为“debug”属性之后就不会优化掉. (2)同一个bank中能设置一个电平. (3)