KMP字符串匹配算法
字符串匹配算法
首先,我们最容易想到的字符串匹配算法就是暴力匹配算法,那么我们首先就来看一下什么是暴力匹配。
暴力匹配算法
暴力的字符串匹配算法很容易写,我们首先来看一下它的运行逻辑:
private int Search(string pat, string txt)
{
int M = pat.Length;
int N = txt.Length;
for (int i = 0; i < N-M; i++)
{
int j;
for (j = 0; j < M; j++)
{
if (pat[j]!=txt[i+j])
{
break;
}
}
//pat全部匹配
if (j==M)
{
return i;
}
}
//txt中不存在pat子串
return -1;
}
对于这种暴力匹配算法,当检测到不匹配的字符时,pat和txt都要同时的回退指针,这在字符串中有很多重复字符的时候,显的异常繁琐。
而KMP的不同之处就在于,它会花费空间来记录一些信息,因此在上述情况中就会显的很聪明。
KMP算法
KMP算法永不回退txt的指针,而是借助DP数组(关于DP数组大家有兴趣的可以自行去查找一下动态规划)中储存的信息把pat移动到正确的位置上继续进行匹配。
下面请看详细代码:
private int[,] dp;
private string pat;
private void Start()
{
KMP("aaab");
int pos = Search("aaacaaab");
Debug.Log("Pos索引位置 :" + pos);
//此处输出匹配字符串索引位置,若未匹配,输出-1
}
private void KMP(string pat)
{
this.pat = pat;
int M = pat.Length;
char[] charPat = pat.ToCharArray();
//dp[状态][字符]=下个状态
dp = new int[M, 256];
//base case
//检测到pat字符串首位字符的时候才会跳转到状态1
dp[0, charPat[0]] = 1;
//影子状态初始为0
int X = 0;
//当前状态j从1开始
for (int j = 1; j < M; j++)
{
for (int c = 0; c < 256; c++)
{
if (charPat[j] == c)
{
dp[j, c] = j + 1;
}
else
{
dp[j, c] = dp[X, c];
}
}
//更新影子状态
X = dp[X, charPat[j]];
}
}
/// <summary>
/// 返回匹配子串的索引开始位置
/// </summary>
/// <param name="txt"></param>
/// <returns></returns>
private int Search(string txt)
{
int N = txt.Length;
int M = pat.Length;
//pat初始状态为0
int j = 0;
for (int i = 0; i < N; i++)
{
//计算pat的下一个状态
j = dp[j, txt.ToCharArray()[i]];
if (j==M)
{
//达到终止态,返回结果
return i - M + 1;
}
}
//未达到终止态,匹配失败
return -1;
}
当前算法可适用于精确搜索功能,模糊搜索期待下回分解!