前几日在微博上看到一则微博是说面试的时候让面试者写一个很简单的字符串匹配都写不出来,于是我就自己去试了一把。结果写出来的是一个最简单粗暴的算法。这里重新学习了一下几个经典的字符串匹配算法,写篇文章以巩固深化自己的理解。本文不打算详细地去讲算法的每一个细节,只是总结一下我觉得比较有用的几个重要点。

简单粗暴法

这货居然还有个学名,Brute Force search,其实翻译过来就是简单粗暴法。

此处略去十行简单粗暴的代码。

KMP匹配算法

网上有很多很多关于KMP算法的博客,一抓一大把,其中我看过的觉得比较好是阮一峰老师的这篇《字符串匹配的KMP算法》,通过图解很通俗易懂。

看完阮一峰老师的那篇文章以后,博拳擦掌,准备大干一场。于是顺着文中的思路,写下了一个KMP算法。如下:

    public static bool IsSubString(string a, string b)
{
if (string.IsNullOrEmpty(a) ||
string.IsNullOrEmpty(b) ||
b.Length > a.Length)
return false;
int[] particalMatchTbl = new int[b.Length];
for (int i = 0; i < b.Length; i++)
{
particalMatchTbl[i] = GetPartialMatchCount(b.Substring(0, i + 1));
} int startPosInA = 0;
int currPosInB = 0; for (startPosInA = 0; startPosInA <= a.Length - b.Length; )
{
for (; currPosInB < b.Length; currPosInB++)
{
if (a[startPosInA + currPosInB] != b[currPosInB])
break;
}
if (currPosInB == b.Length)
return true;
//If position in B string is 0, not need to move in B, just increase pos in A
if (currPosInB == 0)
startPosInA++;
else
{
//currPosInB is the number already matched in string B
//particalMatchTbl[currPosInB - 1] is the max partial match length of matched string
//currPosInB - particalMatchTbl[currPosInB - 1] mean how much char could be skipped
//
// |
//a ABCDAB ABCDABCDABDE
//b ABCDABD
// |
//in this case, in b string, 'ABCDAB' part is matched, AB is the max partial string
//So the first part 'ABCD' could be skipped
//
// |
//a ABCDAB ABCDABCDABDE
//b ABCDABD
// |
startPosInA += currPosInB - particalMatchTbl[currPosInB - 1];
//start from 0, so partial match length is the the next value in B need to check
currPosInB = particalMatchTbl[currPosInB - 1];
}
} return false;
} public static int GetPartialMatchCount(string str)
{
int commonLength = 0;
for (int i = 1; i <= str.Length - 1; i++)
{
if (str.Substring(0, i) == str.Substring(str.Length - i, i))
commonLength = i;
}
return commonLength;
}

虽然这段代码可以完成任务,但是总觉得写的很蹉,特别是求部分匹配表的部分,太没效率了。于是搜了一下高人们都是怎么写的。

我看到的大多数的代码都可以完成任务,有一些也很巧妙,但是读起来就是好吃力,有些没有注释,有些没有说明,有一些文章的格式实在惨不忍睹。最终参考了一下两个来源。

生成局部匹配表部分:

    public static int[] BuildJumpTable(string str)
{
//this table has two meanings:
//1. mean how many chars the prefix and suffix shared.
//2. because the array start from 0, this value also mean if current position is the last matched
// position, which position the match algo should continue in this array.
int[] next = new int[str.Length];
// first char have 0 shared prefix and suffix
next[0] = 0; //i is a stright forward cusor,
for (int i = 1, j = 0; i < str.Length; i++)
{
//use the jump table already generated, if str[i] not match str[j],
//then jump to the pos last matched char point to
while (j > 0 && str[i] != str[j])
{
j = next[j - 1];
} if (str[i] == str[j])
{
j++;
} next[i] = j;
}
return next;
}

我觉得几个比较重要的点:

  • 这里的局部匹配表其实有两层含义,必须明白这两层含义才能够理解这段算法。一个是阮一峰博客中指的最长的匹配字符串,我姑且叫做匹配表;而另一个含义则利用了数组计数从0开始的这个特点,表达的意思是当这个最后一个被匹配的字符,那么下一次匹配从哪个位置开始,姑且叫做跳跃表。
  • j = next[j - 1] 这个地方就是当做跳跃表来使用,而next[i] = j则是表示匹配表,我觉得只有区分开来才能够更好的理解。
  • i是一直增长的数,表示已经匹配到那个位置。而j表达的是下一个要匹配的位置同时又表示已经匹配了多少个,这也是因为数组从0开始才会导致这两个值相等。
  • 比较巧妙的一块代码就是while循环那里,这段代码其实在算这个jump table的时候也已经用了一些kmp算法的思想在里面。如果当前的j和i不匹配,如果j比0大就说明j - 1那个位置一定是匹配的,而next[j-1]跳跃表里面存着恰恰就是下一个要尝试匹配的位置。就这样一直回溯回去就能够找到相等的那个字符,或者是找到第0个。

匹配部分:

    public static bool IsSubString(string a, string b)
{
if (string.IsNullOrEmpty(a) ||
string.IsNullOrEmpty(b) ||
b.Length > a.Length)
return false; int[] next = BuildJumpTable(b); for (int posInA = 0, posInB = 0; posInA < a.Length; posInA++)
{
//if posInB > 0 mean at least posInB - 1 is matched, so got the next position need to match
while (posInB > 0 && a[posInA] != b[posInB])
posInB = next[posInB - 1]; //if they match, move posInB forward
if (a[posInA] == b[posInB])
posInB++; if (posInB == b.Length)
return true;
}
return false;
}

可以看到这段代码和算jump table的代码非常相似,不做解释~

字符串匹配算法 - KMP的更多相关文章

  1. 字符串匹配算法——KMP算法学习

    KMP算法是用来解决字符串的匹配问题的,即在字符串S中寻找字符串P.形式定义:假设存在长度为n的字符数组S[0...n-1],长度为m的字符数组P[0...m-1],是否存在i,使得SiSi+1... ...

  2. 4种字符串匹配算法:KMP(下)

    回顾:4种字符串匹配算法:BS朴素 Rabin-karp(上) 4种字符串匹配算法:有限自动机(中) 1.图解 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R ...

  3. 字符串匹配算法KMP算法

    数据结构中讲到关于字符串匹配算法时,提到朴素匹配算法,和KMP匹配算法. 朴素匹配算法就是简单的一个一个匹配字符,如果遇到不匹配字符那么就在源字符串中迭代下一个位置一个一个的匹配,这样计算起来会有很多 ...

  4. 字符串匹配算法--KMP字符串搜索(Knuth–Morris–Pratt string-searching)C语言实现与讲解

    一.前言   在计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串S内查找一个词W的出现位置.此算法通过运用对这个词在不匹配时本身就包含足够的信息 ...

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

    处理字符串的过程中,难免会遇到字符匹配的问题.常用的字符匹配方法 1. 朴素模式匹配算法(Brute-Force算法) 求子串位置的定位函数Index( S, T, pos). 模式匹配:子串的定位操 ...

  6. [Algorithm] 字符串匹配算法——KMP算法

    1 字符串匹配 字符串匹配是计算机的基本任务之一. 字符串匹配是什么?举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串& ...

  7. 字符串匹配算法——KMP、BM、Sunday

    KMP算法 KMP算法主要包括两个过程,一个是针对子串生成相应的“索引表”,用来保存部分匹配值,第二个步骤是子串匹配. 部分匹配值是指字符串的“前缀”和“后缀”的最长的共有元素的长度.以“ABCDAB ...

  8. KMP Algorithm 字符串匹配算法KMP小结

    这篇小结主要是参考这篇帖子从头到尾彻底理解KMP,不得不佩服原作者,写的真是太详尽了,让博主产生了一种读学术论文的错觉.后来发现原作者是写书的,不由得更加敬佩了.博主不才,尝试着简化一些原帖子的内容, ...

  9. 字符串匹配算法-kmp算法

    一原理: 部分转自:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 字 ...

随机推荐

  1. java web系统中时间比sql server中的日期少2天的解决办法

    系统环境 jdk:1.7 数据库:sql server 2008 问题描述 升级1.7之后查询出来的日期就比数据库中的少2天,降回1.6版本的jdk就正常了. 问题原因及解决办法 国内网站有很多不靠谱 ...

  2. tomcat热部署

    tomcat默认支持热部署,修改文件会自动加载部署,不需要重启容器 server.xml配置如下所示 autoDeploy=”true” — 自动部署 reloadable=”true” — 自动加载

  3. vuex

    英文:(Introduction)中文:https://github.com/vuejs/vuex/issues/176(贡献者努力中)

  4. 安装ganglia

    安装ganglia 1.默认已经配置好相关的主机名和Ip地址映射关系 2.默认已经安装好ssh密码登陆 3.默认已经配置好yum源和相关网络配置(如hosts 可在墙外) 4.服务器端安装(除了yum ...

  5. AndroidAnnotations(Code Diet)android快速开发框架

    最近用了一款很不错的android快速开发框架,1000行的代码瞬间变成几百行,不用你会后悔的 特点: (1) 依赖注入:包括view,extras,系统服务,资源等等(2) 简单的线程模型,通过an ...

  6. Java工程师层级

  7. 转:MYSQL连接字符串参数解析(解释)

    被迫转到MySQL数据库,发现读取数据库时,tinyint类型的值都被转化为boolean了,这样大于1的值都丢失,变成true了.查阅资料MySQL中无Boolean类型,都是存储为tinyint了 ...

  8. Redis为什么使用单进程单线程方式也这么快

    [转] http://www.syyong.com/db/Redis-why-the-use-of-single-process-and-single-threaded-way-so-fast.htm ...

  9. img只显示图片一部分 或 css设置背景图片只显示图片指定区域

    17:14 2016/3/22img只显示图片一部分 或 css设置背景图片只显示图片指定区域 background-position: 100% 56%; 设置背景图片显示图片的哪个坐标区域,图片左 ...

  10. 【BZOJ】4001: [TJOI2015]概率论

    题意 求节点数为\(n\)的有根树期望的叶子结点数.(\(n \le 10^9\)) 分析 神题就打表找规律.. 题解 方案数就是卡特兰数,$h_0=1, h_n = \sum_{i=0}^{n-1} ...