博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
KMP字符串匹配算法及next前缀数组的应用
阅读量:5060 次
发布时间:2019-06-12

本文共 2993 字,大约阅读时间需要 9 分钟。

KMP算法通常是我们学习字符串匹配算法时遇见的第一个算法,另外还有Rabin-Karp, Sunday算法等. 相对于其他字符串匹配算法, kmp在字符串中字符重复率低的情况下并不具备优势,那为什么KMP算法会作为经典的教学算法呢?原因是KMP算法充分利用next前缀数组的信息来优化算法,能解决很多字符串相关问题.

首先上KMP字符串匹配算法,关于KMP算法的详细介绍可以参考,KMP算法

```C++class Solution {public:    int strStr(string haystack, string needle) {    return kmpsearch(haystack, needle);    }    vector
getnext(const string& needle){ vector
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
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结束的后缀.采用平摊分析可得求next数组的时间复杂度的O(N).

添加字符生成最短回文字符串

我们先来看leetcode上的:

题目描述:
给定一个字符串S, 通过在其前面添加字符使其成为回文字符串, 输出最短的回文串
示例: aacecaaa -> aaacecaaa ; abcd -> dcbabcd

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

考虑将字符串逆转,问题转化成求原串的以首字符开始的前缀和逆串以末字符结束的后缀的长度相等且最大的值,这个描述根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
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数组找出最大值即可.

代码如下:

```C++class Solution {public:    string longestRepeatString(const string& s) {        int maxl = 0, start = 0;        vector
next(s.size(), 0); printvec(next); for(int i = 0; i < s.size(); i++) { int mi = 0; next[i] = 0; for(int j = i+1; j < s.size(); j++) { int k = next[j-1]; while(k > 0 && s[j] != s[k+i]){ k = next[k-1]; } next[j] = (k += s[j] == s[k+i]); mi = max(mi, next[j]); } printvec(next); if(mi > maxl) { start = i; maxl = mi; } } return s.substr(start, maxl); }};```

转载于:https://www.cnblogs.com/scaiz/p/4600879.html

你可能感兴趣的文章
js数组复制
查看>>
CoreMontion加速计
查看>>
【php】PDO
查看>>
Find the longest route with the smallest starting point
查看>>
hashMap的源码实现
查看>>
jquery selector 2
查看>>
NSIS API 函数常用备份
查看>>
STL之list(双向链表)
查看>>
朴素贝叶斯应用:垃圾邮件分类
查看>>
php中的常用数组函数(七) 数组合并 array_merge()和array_merge_recursive()
查看>>
《DSP using MATLAB》 Problem 4.9
查看>>
extern "c"
查看>>
利用CSS3-boxshadow绘制“蒙娜丽莎的微笑”
查看>>
scanf()函数
查看>>
USACO4.1.2--Fence Loops
查看>>
MyBatis 一级缓存和二级缓存及ehcache整合
查看>>
未来计算机发展趋势
查看>>
list转datatable,SqlBulkCopy将DataTable中的数据批量插入数据库
查看>>
结构模式--之--门面模式
查看>>
xcode 出现the file couldn't be opened
查看>>