KMP字符串匹配算法及next前缀数组的应用

#KMP字符串匹配算法及next前缀数组的应用
------

KMP算法通常是我们学习字符串匹配算法时遇见的第一个算法,另外还有Rabin-Karp, Sunday算法等. 相对于其他字符串匹配算法, kmp在字符串中字符重复率低的情况下并不具备优势,那为什么KMP算法会作为经典的教学算法呢?

原因可能是:KMP算法充分利用next前缀数组的信息来优化算法,减小时间复杂度的思路在很多字符串相关问题中能给我们启发.

首先上KMP字符串匹配算法, [leetcode在线测试地址](https://leetcode.com/problems/implement-strstr/)

```C++
class Solution {
public:
int strStr(string haystack, string needle) {
return kmpsearch(haystack, needle);
}

vector<int> getnext(const string& needle){
vector<int> next(needle.size(), 0);
for(int i = 1; i < needle.size(); i++){
int j = next[i-1];
while(j != 0 && needle[j] != needle[i]) {
j = next[j-1];
}
next[i] = j += (needle[j] == needle[i]);
}
return next;
}

int kmpsearch(string& haystack, string& needle) {
if(needle.size() == 0) return 0;
vector<int> next = getnext(needle);
int i = 0, j = 0;
while(i < haystack.size() && j < needle.size()) {
while(j != 0 && haystack[i] != needle[j]) {
j = next[j-1];
}
j += haystack[i] == needle[j];
i++;
}
return j == needle.size() ? i - needle.size(): -1;
}
};
```
KMP算法中前缀数组(即next数组)的含义为:对于P = p0 p1 ...pj-1 pj,寻找模式串P中长度最大且相等的以p0开始的前缀和以pj结束的后缀, 关于KMP算法的详细介绍可以参考[从头到尾彻底理解KMP](http://blog.csdn.net/v_july_v/article/details/7041827).

##添加字符生成最短回文字符串
我们先来看leetcode上的[214题](https://leetcode.com/problems/shortest-palindrome/):
题目描述:
给定一个字符串S, 通过在其前面添加字符使其成为回文字符串, 输出最短的回文串
示例: **aacecaaa -> <font color="red">a</font>aacecaaa** ; **abcd -> <font color="red">dcb</font>abcd**

这道题很容易想到首先求出以第一个字符开始的最长的回文字符串的长度,然后将剩余部分添加在前面即为最短的所求回文串,于是问题转化为如何求出以首字符开始的最长回文串长度.

考虑将字符串逆转,问题转化成求原串的以首字符开始的前缀和逆串以末字符结束的后缀的长度相等且最大的值,这个描述根next数组基本就一致了.

于是,解决方法为:
将字符串S逆转后添加到原字符串末尾(为了避免字符串内部干扰中间添加#字符, 考虑S="aaaa")成为字符串T, 如abcd->abcd#dcba, 求T的next数组,next[T.size()-1]即为S以第一个字符开始的最长的回文字符串的长度,从而原问题得解.

代码如下:
```C++
class Solution {
public:
string shortestPalindrome(string s) {
string rs = s;
reverse(rs.begin(), rs.end());
string l = s + "#" + rs;
vector<int> next(l.size(), 0);
for(int i = 1; i < next.size(); i++){
int j = next[i-1];
while(j > 0 && l[i] != l[j])
j = next[j-1];
next[i] = (j += l[i] == l[j]);
}
return rs.substr(0,rs.size()-next[l.size()-1]) + s;
}
};
```

##最长重复子串
题目描述:
给定字符串S,找出其中最长的重复出现的子串
示例: **abcdabef->ab**; **aaaaaa->aaa**

思路:如果重复子串从手字符开始,求出next数组后找出最大值即可, 那么不从首字符开始呢, 我们从其开始计算next数组找出最大值即可

时间: 2024-10-13 16:54:21

KMP字符串匹配算法及next前缀数组的应用的相关文章

KMP字符串匹配算法翔解?

那么首先我们知道,kmp算法是一种字符串匹配算法,那么我们来看一个例子. 比方说,现在我有两段像这样子的字符串: 分别是T和P,很明显,P比T的长度要短很多,我们要做的事情呢,就是找找T中有没有和P相同的一段. 如果按照最简单的办法来做匹配的话,我们一般是一个一个字母的来做. 像这样: 很显然,图中前面3位都是能匹配的,而第四位却不能匹配,怎么办? 这样: 我们就会将整个P字符串向右移动一格,又重新开始,从T中b处与P中第一个a处开始匹配. 如此往复,显然这样是很慢的,因为我们来考虑考虑这样一种

KMP字符串匹配算法——用最容易理解的方式描述

看了数据结构书上对于快速模式匹配算法KMP的介绍,感觉云里雾里.本文根据自己理解,并查资料整理了一种非常清晰简单的字符串匹配算法,并给予实现,自诩原创吧. 字符串匹配是我们经常要用到的一种算法,与普通的匹配算法相比KMP算法效率更高,时间复杂度为O(m+n).下面给予详细讲解: 概念详解 设原字符串为"BBC ABCDAB ABCDABCDABDE",待匹配字符串为"ABCDABD". 首先,字符串"BBC ABCDAB ABCDABCDABDE"

数据结构(三)串---KMP模式匹配算法之获取next数组

(一)获取模式串T的next数组值 1.回顾 我们所知道的KMP算法next数组的作用 next[j]表示当前模式串T的j下标对目标串S的i值失配时,我们应该使用模式串的下标为next[j]接着去和目标串失配的i值进行匹配 而KMP算法的next求值函数 我们可以知道next除了j=1时,next[1]为0,其他情况都是比较前缀和后缀串的相似度(第三种情况是当相似度为0时,next值为0+1=1) next数组,是用来评判前后缀的相识度,而next值,则是等于相似度加一 2.思考 虽然我们知道是

KMP字符串匹配算法详解

KMP算法利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息.时间复杂度O(m+n). Next()函数的详解 把将要进行next计算的字符串S分成 k ,j 前后两串,k代表前串开头所在的序号,j代表后串开头所在的序号,起始的时候j=1,k=0. 我们比较一下前串 后串是否相等,要怎么比较呢,肯定是比较S[j]==S[k],如果相等,那么next[j+1]=k+1,然后j++,k++.关键就是理解这

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

KMP算法是一种非常高效和常用的算法.其核心就是通过预处理一个寻找公共最大前后缀的 Next[ ] 数组,减少匹配失败时的重复无效匹配. next数组本质:next[ i ] = j 表示下标以 i - j 为起点,i为终点的后缀和下标以0为起点,j为终点的前缀相等. 复制一些别人的图片用来帮助理解next是什么. 然后是kmp算法的思想原理: 下图是主串为:ababaeaba 字串为:ababacd 的一个例子: 例题: 代码: #include<iostream> using namesp

【算法】KMP字符串匹配算法

[原理] (1)next数组原理 (2)特殊情况的处理(巧妙增设哨兵) (3)递推法构造next[]表 [实现代码] #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 100; char t[maxn]; //text char p[maxn]; int next[maxn]; void getNext(){ int m = strlen

KMP字符串匹配算法

1 #include<iostream> 2 #include<string> 3 #include<vector> 4 using namespace std; 5 bool matched(string s,int k,int i) 6 { 7 bool result=true; 8 int p=0; 9 int q=i; 10 while(p<k) 11 { 12 if(s[p]==s[q]) 13 { 14 p++;q--; 15 } 16 else 17

28. Implement strStr()(KMP字符串匹配算法)

Implement strStr(). Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack. Example 1: Input: haystack = "hello", needle = "ll" Output: 2 Example 2: Input: haystack = "aaaaa",

字符串匹配算法KMP算法

数据结构中讲到关于字符串匹配算法时,提到朴素匹配算法,和KMP匹配算法. 朴素匹配算法就是简单的一个一个匹配字符,如果遇到不匹配字符那么就在源字符串中迭代下一个位置一个一个的匹配,这样计算起来会有很多多余的不符合的匹配做了冗余的比较.假设源字符串长n,字串长m 该算法最差时间复杂度为 m*(n-m+1),记为O(n*m);这里不做过多解释朴素匹配算法. KMP算法: kmp算法不是在源字符串中下手,他是从字串下手,比如我要在源字符串(acabaabaabcacaabc)中匹配一个字符串字串(ab