这里分享下我学习KMP的心得
KMP算法是三位计算机科学家发明的字符串匹配算法。
从暴力逐个比对到最大公共前后缀优化
next数组
假设已经得到next数组,使用数组进行字符串匹配的流程如上,代码如下
const int N = 100010, M = 1000010;
int n, m;
int ne[N];
char s[M], p[N];
{
for (int i = 1, j = 0; i <= m; i ++ )
{
while (j && s[i] != p[j + 1]) j = ne[j];
if (s[i] == p[j + 1]) j ++ ;
if (j == n)
{
//ok 得到答案
return 0;
}
}
}
//==================================================================
下面我们来进行next数组的计算
Next数组就是计算某个坐标之前的字符串的能匹配的前缀与后缀的长度
本质上就是自己和自己的匹配
int n, m;
int ne[N];
char s[M], p[N];
for (int i = 2, j = 0; i <= n; i ++ )
{
while (j && p[i] != p[j + 1]) j = ne[j];
if (p[i] == p[j + 1]) j ++ ;
ne[i] = j;
}
下面来试试代码实现解决Leetcode 28. 实现 strStr()
地址 https://leetcode-cn.com/problems/implement-strstr/
实现 strStr() 函数。
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。
如果不存在,则返回 -1 。
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与 C 语言的 strstr() 以及 Java 的 indexOf() 定义相符。
示例 1:
输入:haystack = "hello", needle = "ll"
输出:2
示例 2:
输入:haystack = "aaaaa", needle = "bba"
输出:-1
示例 3:
输入:haystack = "", needle = ""
输出:0
提示:
0 <= haystack.length, needle.length <= 5 * 104
haystack 和 needle 仅由小写英文字符组成
解答 使用kmp算法解决该题
class Solution {
public:
int ne[50010];
int strStr(string haystack, string needle) {
if (needle.empty()) return 0;
memset(ne, 0, sizeof ne);
int m = haystack.size();
int n = needle.size();
haystack.insert(haystack.begin(), '#');
needle.insert(needle.begin(), '#');
for (int i = 2, j = 0; i <= n; i++)
{
while (j && needle[i] != needle[j + 1]) j = ne[j];
if (needle[i] == needle[j + 1]) j++;
ne[i] = j;
}
for (int i = 1, j = 0; i <= m; i++)
{
while (j && haystack[i] != needle[j + 1]) j = ne[j];
if (haystack[i] == needle[j + 1]) j++;
if (j == n)
{
return i - n;
}
}
return -1;
}
};
Leetcode 1392 最长快乐前缀
地址 https://leetcode-cn.com/problems/longest-happy-prefix/
「快乐前缀」是在原字符串中既是 非空 前缀也是后缀(不包括原字符串自身)的字符串。
给你一个字符串 s,请你返回它的 最长快乐前缀。
如果不存在满足题意的前缀,则返回一个空字符串。
示例 1:
输入:s = "level"
输出:"l"
解释:不包括 s 自己,一共有 4 个前缀("l", "le", "lev", "leve")和 4 个后缀("l", "el", "vel", "evel")。
最长的既是前缀也是后缀的字符串是 "l" 。
示例 2:
输入:s = "ababab"
输出:"abab"
解释:"abab" 是最长的既是前缀也是后缀的字符串。题目允许前后缀在原字符串中重叠。
示例 3:
输入:s = "leetcodeleet"
输出:"leet"
示例 4:
输入:s = "a"
输出:""
提示:
1 <= s.length <= 10^5
s 只含有小写英文字母
解法 求最长的公共前缀后缀 就是kmp中next数组的过程
class Solution {
public:
int ne[100010];
string longestPrefix(string s) {
int n = s.size();
s.insert(s.begin(), '#');
memset(ne, 0, sizeof ne);
for (int i = 2, j = 0; i <= n; i++)
{
while (j && s[i] != s[j + 1]) j = ne[j];
if (s[i] == s[j + 1]) j++;
ne[i] = j;
}
int len = ne[s.size()-1];
return s.substr(1,len);
}
};