一:Brute force

从源串的第一个字符开始扫描,逐一与模式串的对应字符进行匹配,若该组字符匹配,则检测下一组字符,如遇失配,则退回到源串的第二个字符,重复上述步骤,直到整个模式串在源串中找到匹配,或者已经扫描完整个源串也没能够完成匹配为止。

缺点:假如我们从头开始匹配str1和str2,当匹配到str1[i]时,发现str2[i]!=str1[i],这时我们就回到str1起始匹配的地方,把str2右移一位对准str1下一字符作为起点,进行匹配。由于上一次匹配到了str1[i],那么重新开始匹配时,新匹配起点~str1[i]这段子串又要被重新匹配

二:KMP

暴力搜索的缺点在于单纯地从原来匹配起点右移一位重新匹配,效率低下并且没有好好利用上一次匹配时得出的有效信息

KMP算法的出发点为:从上一次匹配过程中,检测出有效信息,使下一次匹配不是单纯地右移一位开始匹配,而是跳过一段不必要尝试的子串,直接从下一有可能匹配成功的起点开始匹配。

概念准备:

前缀:字符串A = "abcde",那么a,ab,abc,abcd,abcde都是A的前缀,前缀其实就是字符串A从左往右、从头开始依次取长度为1、2、3...str.length()的子串。

后缀:字符串A = "abcde",那么abcde,bcde,cde,de,e都是A的后缀,同理,后缀就是依次从A的开头、第二位,第三位...最后一位开始截取,取到尾部的子串。

真前缀、真后缀:即不等于字符串本身的前缀、后缀子串。

kmp算法的核心:

计算字符串f每一个位置之前的子串的前缀和真后缀公共部分的最大长度(不包括子串本身,否则最大长度始终是子串本身)。当每次比较到两个字符串的字符不同时,我们就可以根据当前比较位置的最大公共长度将字符串f右移(已匹配长度-最大公共长度)位,重新开始匹配。

我们把查找的字符串成为模式串,KMP算法的代码实际上分两部分:

1:预处理模式串,得到next[]数组(next数组为:对于模式串的每一位j,当位j与主串不匹配时,模式串下一个匹配起点是模式串中的哪位);【相对移动,这里不求最大长度和模式串右移多少位,而是直接求模式串右移后,新的匹配的起点的位置(因为右移后,前缀是匹配的,所以不是从模式串开头进行匹配,而是从前缀的后一位开始)】

2:匹配字符串,每当匹配到不相同位时,使用next[]得到模式串下一个用来匹配的起点

 public static int[] next(char[] t) {
int[] next = new int[t.length];
next[0] = -1;
int i = 0;
int j = -1;
while (i < t.length - 1) {
if (j == -1 || t[i] == t[j]) {
i++;
j++;
if (t[i] != t[j]) {
next[i] = j;
} else {
next[i] = next[j];
}
} else {
j = next[j];
}
}
return next;
} public static int KMP_Index(char[] s, char[] t) {
int[] next = next(t);
int i = 0;
int j = 0;
while (i <= s.length - 1 && j <= t.length - 1) {
if (j == -1 || s[i] == t[j]) {
i++;
j++;
} else {
j = next[j];
}
}
if (j < t.length) {
return -1;
} else
return i - t.length; // 返回模式串在主串中的头下标
}

三:Sunday

简单、快速的匹配算法。

思路如下:摘自:http://blog.csdn.net/laojiu_/article/details/50767615

假设我们有如下字符串:
A = "LESSONS TEARNED IN SOFTWARE TE";
B = "SOFTWARE";
Sunday算法的大致原理是:
先从左到右,两个字符串逐个字符比较,i指向主串下标,j指向模式串下标
开始的时候,我们让i = 0, 指向A的第一个字符; j = 0 指向B的第一个字符,分别为"L"和"S",不等;这个时候,找到位于A字串中位于B字符串长度后面的第一个字符,下标为m,即下图字符"T",然后在模式字符串B中从后向前查找是否存在"T";

可以看到下图模式串的T,下标为k

将相等的字符对齐(对齐的方法为:令i移动,j仍指向模式串开头):

再次比较A[i]和B[j],不等,这时再次寻找主串中在模式串后面的那个字符,

我们看到,模式串的最后一个字符与m指向的主串字符相等,再次对齐

这时,主串i对应的字符是S,j对应的子串字符也是S。则逐位比较,同步移动下标:i++, j++

现在再次不等,找到A中的m,指向字符"D",

代码实现:

    //从后向前寻找目标字符下标
private int contains(char[] chars,char target){
for(int i = chars.length-1 ; i >= 0; i--){
if(chars[i] == target){
return i ;
}
}
return -1;
} //sunday算法
public int Sunday(String dest , String pattern){ char[] destchars = dest.toCharArray();
char[] patternchars = pattern.toCharArray(); int i = 0;
int j = 0;
//控制边界
while(i <= (dest.length() - pattern.length() + j ) ){
if( destchars[i] != patternchars[j] ){//对应位不相同
if(i == (dest.length() - pattern.length() + j )){//已经末尾对齐
return -1;
}
//还未到主串末尾,则继续下面操作
//在模式串中。查找主串中对应模式串末尾的下一位字符在模式串中的下标
int pos = contains(patternchars,destchars[i+pattern.length()-j]);
if( pos== -1){//若没有,则直接把模式串对齐末尾的下一位
i = i + (pattern.length() - j)+1;
j = 0 ;
}else{
i = i + (pattern.length() - j)-pos;
j = 0;
}
}else{//对应位相同
if(j == (pattern.length() - 1)){//如果对应位已经到达模式串末尾,则匹配成功
return i-j+1;
}else{//未到末尾,则比较下一位
i++;
j++;
}
}
}
}

字符串匹配算法——BF、KMP、Sunday的更多相关文章

  1. 数据结构学习之字符串匹配算法(BF||KMP)

    数据结构学习之字符串匹配算法(BF||KMP) 0x1 实验目的 ​ 通过实验深入了解字符串常用的匹配算法(BF暴力匹配.KMP.优化KMP算法)思想. 0x2 实验要求 ​ 编写出BF暴力匹配.KM ...

  2. 字符串匹配算法之 kmp算法 (python版)

    字符串匹配算法之 kmp算法 (python版) 1.什么是KMP算法 KMP是三位大牛:D.E.Knuth.J.H.MorriT和V.R.Pratt同时发现的.其中第一位就是<计算机程序设计艺 ...

  3. Python 细聊从暴力(BF)字符串匹配算法到 KMP 算法之间的精妙变化

    1. 字符串匹配算法 所谓字符串匹配算法,简单地说就是在一个目标字符串中查找是否存在另一个模式字符串.如在字符串 "ABCDEFG" 中查找是否存在 "EF" ...

  4. 动画演示Sunday字符串匹配算法——比KMP算法快七倍!极易理解!

    前言 上一篇我用动画的方式向大家详细说明了KMP算法(没看过的同学可以回去看看). 这次我依旧采用动画的方式向大家介绍另一个你用一次就会爱上的字符串匹配算法:Sunday算法,希望能收获你的点赞关注收 ...

  5. 字符串匹配算法之————KMP算法

    上一篇中讲到暴力法字符串匹配算法,但是暴力法明显存在这样一个问题:一次只移动一个字符.但实际上,针对不同的匹配情况,每次移动的间隔可以更大,没有必要每次只是移动一位: 关于KMP算法的描述,推荐一篇博 ...

  6. 字符串匹配算法之kmp算法

    kmp算法是一种效率非常高的字符串匹配算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,所以简称KMP算法 算法思想 在一个字符串中查找另一个字符串时,会遇到如下图的情况 我们通常 ...

  7. 字符串匹配算法(三)-KMP算法

    今天我们来聊一下字符串匹配算法里最著名的算法-KMP算法,KMP算法的全称是 Knuth Morris Pratt 算法,是根据三位作者(D.E.Knuth,J.H.Morris 和 V.R.Prat ...

  8. 字符串KMP——用途广泛的字符串匹配算法 + 扩展KMP——特殊定义的字符串匹配

    引 入 引入 引入 " SY 和 WYX 在看毛片.(几 毛 钱买到的动作 片,毛 片) WYX 突然想回味一个片段,但是只记得台词里面有一句挺长的 " ∗ ∗ ∗ ∗ **** ...

  9. 字符串匹配算法BF和KMP总结

    背景 来看一道leetcode题目: Implement strStr(). Returns the index of the first occurrence of needle in haysta ...

随机推荐

  1. 用自定义的RoundImageView来实现圆形图片(可加边框)

    本文的控件来自:http://blog.csdn.net/alan_biao/article/details/17379925 这个控件不同于之前介绍过的那个框架,这个仅仅能过将图片裁剪为圆形,没能弄 ...

  2. SVG.js Mask覆盖和ClipPath裁剪

    一.SVG.Mask 覆盖物设置 1. var draw = SVG('svg1').size(300, 300); //SVG.Mask 覆盖物设置 var ellipse = draw.ellip ...

  3. Java 集合细节(二):asList 的缺陷

    在实际开发过程中我们经常使用 asList 讲数组转换为 List,这个方法使用起来非常方便,但是 asList 方法存在几个缺陷: 一.避免使用基本数据类型数组转换为列表 使用 8 个基本类型数组转 ...

  4. 利用Visual Studio 2013 开发微软云Windows Azure配置指南(针对中国大陆)

    微软云在中国是由“世纪互联”营运的,所以如果你用Visual Stuido 2003全通通用账户开发微软云,会有问题,这是他的不方便支持.好处是,因为是在大陆营运,所以速度比较快. (1)打开官网 h ...

  5. Asp.Net MVC2.0 Url 路由入门---实例篇 【转】

    本篇主要讲述Routing组件的作用,以及举几个实例来学习Asp.Net MVC2.0 Url路由技术. 接着上一篇开始讲,我们在Global.asax中注册一条路由后,我们的请求是怎么转到相应的Vi ...

  6. tfjob的一篇文章,跟公司内使用方式类似

    可以看一下这篇文章: https://yq.aliyun.com/articles/600601?spm=a2c4e.11153940.blogcont602109.12.2e241125zH1kNB

  7. go语言之进阶篇接口的定义和实现以及接口的继承

    1.接口的定义和实现以及接口的继承 示例: package main import "fmt" //定义接口类型 type Humaner interface { //方法,只有声 ...

  8. asp.net mvc源码分析-ModelValidatorProviders 客户端的验证

    几年写过asp.net mvc源码分析-ModelValidatorProviders 当时主要是考虑mvc的流程对,客户端的验证也只是简单的提及了一下,现在我们来仔细看一下客户端的验证. 如图所示, ...

  9. asp.net单元测试及查看代码覆盖率详细示例

    在vs2008中创建单元测试 一,打开vs2008,创建一个类库VSTSDemo.因为我在学习的时候用的就是vs2008,其它版本的vs,方法应该差不多,大家自己研究吧 :) 删除掉默认生成的类,然后 ...

  10. Html-文档类型(DTD)和DOCTYPE

    在正式介绍文档类型(DTD)和DOCTYPE之前,我们需要先了解HTML和XHTML的之间的区别,现在Html5已经慢慢的成为主流,之前的数十年一直都是Html4.01的天下,Html4.01于199 ...