字符串匹配是字符串的一种基本操作:给定一个长度为 M 的文本和一个长度为 N 的模式串,在文本中找到一个和该模式相符的子字符串,并返回该字字符串在文本中的位置。

KMP 算法,全称是 Knuth-Morris-Pratt 算法,以三个发明者命名,开头的那个K就是著名科学家 Donald Knuth 。KMP 算法的关键是求 next 数组。next 数组的长度为模式串的长度。next 数组中每个值代表模式串中当前字符前面的字符串中,有多大长度的相同前缀后缀。

Boyer-Moore 算法在实际应用中比 KMP 算法效率高,据说各种文本编辑器的"查找"功能(Ctrl+F),包括 linux 里的 grep 命令,都是采用 Boyer-Moore 算法。该算法有“坏字符”和“好后缀”两个概念。主要特点是字符串从后往前匹配。

Sunday 算法跟 KMP 算法一样,是从前往后匹配。在匹配失败时,关注文本串中参加匹配的最末位字符的下一位字符,如果该字符不在模式串中,则整个模式串移动到该字符之后。如果该字符在模式串中,将模式串右移使对应的字符对齐。

关于这几种算法的详细介绍,可参考该博客

下面分别给出暴力匹配、KMP 算法、Boyer-Moore 算法和 Sunday 算法的 Java 实现。

暴力匹配:

public static int forceSearch(String txt, String pat) {
int M = txt.length();
int N = pat.length();
for (int i = 0; i <= M - N; i++) {
int j;
for (j = 0; j < N; j++) {
if (txt.charAt(i + j) != pat.charAt(j))
break;
}
if (j == N)
return i;
}
return -1;
}

KMP 算法:

public class KMP {
public static int KMPSearch(String txt, String pat, int[] next) {
int M = txt.length();
int N = pat.length();
int i = 0;
int j = 0;
while (i < M && j < N) {
if (j == -1 || txt.charAt(i) == pat.charAt(j)) {
i++;
j++;
} else {
j = next[j];
}
}
if (j == N)
return i - j;
else
return -1;
} public static void getNext(String pat, int[] next) {
int N = pat.length();
next[0] = -1;
int k = -1;
int j = 0;
while (j < N - 1) {
if (k == -1 || pat.charAt(j) == pat.charAt(k)) {
++k;
++j;
next[j] = k;
} else
k = next[k];
}
} public static void main(String[] args) {
String txt = "BBC ABCDAB CDABABCDABCDABDE";
String pat = "ABCDABD";
int[] next = new int[pat.length()];
getNext(pat, next);
System.out.println(KMPSearch(txt, pat, next));
}
}

Boyer-Moore 算法

public class BoyerMoore {
public static void getRight(String pat, int[] right) {
for (int i = 0; i < 256; i++){
right[i] = -1;
}
for (int i = 0; i < pat.length(); i++) {
right[pat.charAt(i)] = i;
}
} public static int BoyerMooreSearch(String txt, String pat, int[] right) {
int M = txt.length();
int N = pat.length();
int skip;
for (int i = 0; i <= M - N; i += skip) {
skip = 0;
for (int j = N - 1; j >= 0; j--) {
if (pat.charAt(j) != txt.charAt(i + j)) {
skip = j - right[txt.charAt(i + j)];
if (skip < 1){
skip = 1;
}
break;
}
}
if (skip == 0)
return i;
}
return -1;
} public static void main(String[] args) {
String txt = "BBC ABCDAB AACDABABCDABCDABDE";
String pat = "ABCDABD";
int[] right = new int[256];
getRight(pat,right);
System.out.println(BoyerMooreSearch(txt, pat, right));
}
}

Sunday算法

public class Sunday {
public static int getIndex(String pat, Character c) {
for (int i = pat.length() - 1; i >= 0; i--) {
if (pat.charAt(i) == c)
return i;
}
return -1;
} public static int SundaySearch(String txt, String pat) {
int M = txt.length();
int N = pat.length();
int i, j;
int skip = -1;
for (i = 0; i <= M - N; i += skip) {
for (j = 0; j < N; j++) {
if (txt.charAt(i + j) != pat.charAt(j)){
if (i == M - N)
break;
skip = N - getIndex(pat, txt.charAt(i + N));
break;
}
}
if (j == N)
return i;
}
return -1;
}
public static void main(String[] args) {
String txt = "BBC ABCDAB AACDABABCDABCDABD";
String pat = "ABCDABD";
System.out.println(SundaySearch(txt, pat));
}
}

字符串查找算法总结(暴力匹配、KMP 算法、Boyer-Moore 算法和 Sunday 算法)的更多相关文章

  1. BM算法和Sunday快速字符串匹配算法

    BM算法研究了很久了,说实话BM算法的资料还是比较少的,之前找了个资料看了,还是觉得有点生涩难懂,找了篇更好的和算法更好的,总算是把BM算法搞懂了. 1977年,Robert S.Boyer和J St ...

  2. 词性标注算法之CLAWS算法和VOLSUNGA算法

    背景知识 词性标注:将句子中兼类词的词性根据上下文唯一地确定下来. 一.基于规则的词性标注方法 1.原理 利用事先制定好的规则对具有多个词性的词进行消歧,最后保留一个正确的词性. 2.步骤 ①对词性歧 ...

  3. 使用Apriori算法和FP-growth算法进行关联分析

    系列文章:<机器学习实战>学习笔记 最近看了<机器学习实战>中的第11章(使用Apriori算法进行关联分析)和第12章(使用FP-growth算法来高效发现频繁项集).正如章 ...

  4. Prim算法和Kruskal算法

       Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...

  5. 最小生成树---Prim算法和Kruskal算法

    Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...

  6. mahout中kmeans算法和Canopy算法实现原理

    本文讲一下mahout中kmeans算法和Canopy算法实现原理. 一. Kmeans是一个很经典的聚类算法,我想大家都非常熟悉.虽然算法较为简单,在实际应用中却可以有不错的效果:其算法原理也决定了 ...

  7. 转载:最小生成树-Prim算法和Kruskal算法

    本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...

  8. 0-1背包的动态规划算法,部分背包的贪心算法和DP算法------算法导论

    一.问题描述 0-1背包问题,部分背包问题.分别实现0-1背包的DP算法,部分背包的贪心算法和DP算法. 二.算法原理 (1)0-1背包的DP算法 0-1背包问题:有n件物品和一个容量为W的背包.第i ...

  9. 用Spark学习FP Tree算法和PrefixSpan算法

    在FP Tree算法原理总结和PrefixSpan算法原理总结中,我们对FP Tree和PrefixSpan这两种关联算法的原理做了总结,这里就从实践的角度介绍如何使用这两个算法.由于scikit-l ...

随机推荐

  1. 1)Linux学习笔记:crontab命令

    crond简介 crond是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程 配置文件 ``` SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin: ...

  2. DNS分析

    一.DNS服务器 区域传送: 区域(zone)和 域(domain) 区域:物理概念 域:逻辑概念 区域数据库文件: 资源记录:RR 有类型:A AAAA PTR SOA NS CNAME MX SO ...

  3. JavaWeb:EL & JSTL

    EL:全名为 Expression Language 1.语法:${sessionScope.user.sex}(从Session 的范围中,取得用户的性别), 所有的EL 都是以 ${  为起始,以 ...

  4. django QuerySet里那些常用又不常见的技巧

    QuerySet 像Entry.Objects.all(),这些操作返回的是一个QuerySet对象,这个对象比较特别,并不是执行Objects.all(),或者filter之后就会与数据库交互,具体 ...

  5. ubuntu 设置主屏和副屏

    作为一个程序员,从开始使用双屏之后,一个显示屏开发,那种感觉,就是不好... 好吧,刚换到ubuntu,笔记本一个显示屏,外接了一个HDMI的显示器,由于书桌的位置,只有把HDMI的显示屏放在笔记本的 ...

  6. mysql授权远程用户连接(权限最小化原则)

    1.进入MySQL,创建一个新用户root,密码为root: 格式:grant 权限 on 数据库名.表名 to 用户@登录主机 identified by "用户密码"; gra ...

  7. Quartz2D 之 简单使用

    1. 获取Graphics Context CGContextRef ctx = UIGraphicsGetCurrentContext(); 2. 最后的渲染接口 CGContextStrokePa ...

  8. HTML5定稿:手机App将三年内消失,互联网世界的第二次大战

    HTML5与app以对立竞争的产品形态展现在大众视野.从去年开始又有一大批技术派或者创业者盯向html5领域,移动游戏的爆发和微信朋友圈等众多平台为HTML5导流,能不能颠覆,或许只是时间上的问题. ...

  9. 动软模板系列二(Model层模板)

    动软模板其实和CodeSmith的模板差不多 实现的原理是一样的,但是CodeSmith貌似只支持表生成,而且不够“国人化”,所以打算研究下动软的模板,如果熟练掌握后想必以后开发项目效率可以提高很多了 ...

  10. easyUI resizable组件使用

    easyUI resizable组件使用: <!DOCTYPE html> <html lang="en"> <head> <meta c ...