字符串匹配算法 - KMP
前几日在微博上看到一则微博是说面试的时候让面试者写一个很简单的字符串匹配都写不出来,于是我就自己去试了一把。结果写出来的是一个最简单粗暴的算法。这里重新学习了一下几个经典的字符串匹配算法,写篇文章以巩固深化自己的理解。本文不打算详细地去讲算法的每一个细节,只是总结一下我觉得比较有用的几个重要点。
简单粗暴法
这货居然还有个学名,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;
}
虽然这段代码可以完成任务,但是总觉得写的很蹉,特别是求部分匹配表的部分,太没效率了。于是搜了一下高人们都是怎么写的。
我看到的大多数的代码都可以完成任务,有一些也很巧妙,但是读起来就是好吃力,有些没有注释,有些没有说明,有一些文章的格式实在惨不忍睹。最终参考了一下两个来源。
- KMP算法实现 -- 代码可读性较好,感觉主要还是参考了Linux中的实现
- Linux KMP 源码
生成局部匹配表部分:
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的更多相关文章
- 字符串匹配算法——KMP算法学习
KMP算法是用来解决字符串的匹配问题的,即在字符串S中寻找字符串P.形式定义:假设存在长度为n的字符数组S[0...n-1],长度为m的字符数组P[0...m-1],是否存在i,使得SiSi+1... ...
- 4种字符串匹配算法:KMP(下)
回顾:4种字符串匹配算法:BS朴素 Rabin-karp(上) 4种字符串匹配算法:有限自动机(中) 1.图解 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R ...
- 字符串匹配算法KMP算法
数据结构中讲到关于字符串匹配算法时,提到朴素匹配算法,和KMP匹配算法. 朴素匹配算法就是简单的一个一个匹配字符,如果遇到不匹配字符那么就在源字符串中迭代下一个位置一个一个的匹配,这样计算起来会有很多 ...
- 字符串匹配算法--KMP字符串搜索(Knuth–Morris–Pratt string-searching)C语言实现与讲解
一.前言 在计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串S内查找一个词W的出现位置.此算法通过运用对这个词在不匹配时本身就包含足够的信息 ...
- 字符串匹配算法——KMP算法
处理字符串的过程中,难免会遇到字符匹配的问题.常用的字符匹配方法 1. 朴素模式匹配算法(Brute-Force算法) 求子串位置的定位函数Index( S, T, pos). 模式匹配:子串的定位操 ...
- [Algorithm] 字符串匹配算法——KMP算法
1 字符串匹配 字符串匹配是计算机的基本任务之一. 字符串匹配是什么?举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串& ...
- 字符串匹配算法——KMP、BM、Sunday
KMP算法 KMP算法主要包括两个过程,一个是针对子串生成相应的“索引表”,用来保存部分匹配值,第二个步骤是子串匹配. 部分匹配值是指字符串的“前缀”和“后缀”的最长的共有元素的长度.以“ABCDAB ...
- KMP Algorithm 字符串匹配算法KMP小结
这篇小结主要是参考这篇帖子从头到尾彻底理解KMP,不得不佩服原作者,写的真是太详尽了,让博主产生了一种读学术论文的错觉.后来发现原作者是写书的,不由得更加敬佩了.博主不才,尝试着简化一些原帖子的内容, ...
- 字符串匹配算法-kmp算法
一原理: 部分转自:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 字 ...
随机推荐
- win7 下安装RVCT
由于项目的需求,需要使用RVCT 3.1: 一看此包的发布日期,老的吓人,但没办法,只能硬着头皮安装: 环境:WIN7 安装软件RVCT 3.1 build 569 license:由于需要编译的代码 ...
- Windows8 UI MessageBox In DevExpress
// custom messagebox using System; using System.Drawing; using System.Windows.Forms; using DevExpres ...
- ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
有时候,当我们使用"mysql"."mysqladmin"."mysqldump"等命令管理数据库时,服务器抛出类似如下错误: 一.错误现场 ...
- Fragment滑动切换简单案例
Fragment的产生与介绍Android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视.针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后拷贝一份,修改布局以适应平板神 ...
- 【iOS atomic、nonatomic、assign、copy、retain、weak、strong】的定义和区别详解
一.atomic与nonatomic 1.相同点 都是为对象添加get和set方法 2.不同点 atomic为get方法加了一把安全锁(及原子锁),使得方法get线程安全,执行效率慢 nonatomi ...
- 1.Linux常用命令
命令名称:ls 格式: ls [-选项] [参数] 注:中括号表示可选 命令路径:/bin/ls 功能描述:显示信息 例如: 选项 -a 显示所有的文件,包括隐藏文件,(以 . 开头的文件) -l ...
- 使用命令行+ideal 工具实现本地代码项目提交
在 OSChina 上建立一个私用的项目 mkdir test cd test git init touch README.md git add README.md git commit -m &qu ...
- 如何查看bash shell 帮助信息?
man bash 查看bash的命令帮助 info bash 查看bash的文档 help 命令显示bash支持的命令: 如果想看某个命令的帮助可以 help 命令.如 help cd 对bash的命 ...
- ASCII和16进制对照表
十六进制代码 MCS 字符或缩写 DEC 多国字符名 ASCII 控制字符 1 00 NUL 空字符 01 SOH 标题起始 (Ctrl/A) 02 STX 文本起始 (Ctrl/B) 03 ETX ...
- java项目启动后,数据库字段生成 user_name带下划线这种形式的
hibernate 5.0 版本以上去掉了 hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy 这个属性,如果非 ...