字符串匹配算法 - 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 字 ...
随机推荐
- FZU 2137 奇异字符串 后缀树组+RMQ
题目连接:http://acm.fzu.edu.cn/problem.php?pid=2137 题解: 枚举x位置,向左右延伸计算答案 如何计算答案:对字符串建立SA,那么对于想双延伸的长度L,假如有 ...
- Spring的JDBC模板
Spring对持久层技术支持 JDBC : org.springframework.jdbc.core.JdbcTemplate Hibernate3.0 : org.springframework. ...
- C++模板分离
在正常情况下,c++模板是不允许在头文件声明,在cpp文件中实现.那是因为在cpp文件在编译时内存必须要给它分配储存空间.但是模板本身是一种泛型,在没有明确定义声明类型前,编译器也无法知道它的大小.所 ...
- 递推+高精度 UVA 10497 Sweet Child Makes Trouble(可爱的孩子惹麻烦)
题目链接 题意: n个物品全部乱序排列(都不在原来的位置)的方案数. 思路: dp[i]表示i个物品都乱序排序的方案数,所以状态转移方程.考虑i-1个物品乱序,放入第i个物品一定要和i-1个的其中一个 ...
- centos yum换阿里云源
阿里云Linux安装软件镜像源 阿里云是最近新出的一个镜像源.得益与阿里云的高速发展,这么大的需求,肯定会推出自己的镜像源. 阿里云Linux安装镜像源地址:http://mirrors.aliyun ...
- C++Primer学习笔记(1)
序: 为了重新扎扎实实地再深入学习一遍C++,我选择了C++ Primer这本经典.又开了这个系列的随笔,用于记录学习过程中遇到的一些有趣的问题和心得.同时,也是想通过写随笔的方式督促自己不断进步,争 ...
- appzapper注册码
Appzapper for mac是MAC OS上的一款软件,可以非常方便的卸载自己不喜欢的软件,非常的快速便捷,卸载的时候不会有残留. 下载地址:http://www.pc6.com/mac/114 ...
- 关于WM_GETTEXT的应用
HWND hw = ::FindWindow(NULL,"Form1"); HWND hw2 = ::FindWindowEx(hw,NULL,NULL,NULL); int le ...
- HDU3948 & 回文树模板
Description: 求本质不同回文子串的个数 Solution: 回文树模板,学一学贴一贴啊... Code: /*================================= # Cre ...
- T-SQL Recipes之Separating elements
Separating elements Separating elements is a classic T-SQL challenge. It involves a table called Arr ...