KMP算法 字符串匹配
解题思路
总算理解KMP算法
前缀表求得是最大的公共前后缀长度 最长size-1, e.g siis 不是求回文串 所以不能动态规划
siis ==> [0,0 ,1 ] sii vs iis ,
前缀是指string[0:size-1]
后缀是指string[1:size]
无论是求前缀表还是比较模式串与目标字符串, 都需要用到“回退”
写代码时候 最后结合一个例子来写 写出框架
代码
class Solution {
public:
int strStr(string haystack, string needle)
{
if(needle.empty()) return 0;
//首先 O(m) 求出next 数组
// 前缀和后缀最大相同
// j i
//a a b a a f
std::vector<int> next(needle.size(),0);
int j=0;
for(int i=1;i<needle.size(); i++)
{
//回退
while( j>0 && needle[i] != needle[j] ) j= next[j-1];
if(needle[i] == needle[j] ) j++;
next[i] =j;
}
// for(auto t:next) std::cout << t << " ";
// std::cout << std::endl;
// aabaa b aafa
// aabaa f
// -------
// aabaa b aafa
// aa b aaf //确保 needle[j] = hay[i]
// --------
// aabaabaa f a
// aabaa f ok needle_idx = needle.size
// else -------
// aabaabaa f a
// aabaa e
// ---------
// aabaabaa f a
// aa b aae
// ----------
// aabaabaafa when hay end, needle_idx != size return -1
// aa b aae
//O(n) 根据前缀表进行匹配
j=0;
for(int i=0;i<haystack.size();i++)
{
//回退 确保 needle[j] = hay[i]
std::cout << i << " " << j << std::endl;
while( j>0 && needle[j]!= haystack[i] )
{
j = next[j-1];
}
if(needle[j]== haystack[i]) j++;
if(j== needle.size() ) return i- needle.size()+1;
}
//e.g
// "aabaabaafa"
// "aabaaf"
// output:
// 0 0
// 1 1
// 2 2
// 3 3
// 4 4
// 5 5
// 6 3
// 7 4
// 8 5
return -1;
}
};
暴力解法代码,顺便回顾下动态规划
class Solution {
public:
int strStr(string haystack, string needle) {
//动态规划解法 参考 https://leetcode-cn.com/problems/implement-strstr/solution/dong-tai-gui-hua-jie-fa-by-xqlsq/
// dp[i][j] 表示 needle[..j] 在 hay[...i]出现的位置
// 显然
// if hay[i] = hay[j] , dp[i][j]= dp[i-1][j-1]
// 举例验证 ,注意初始化时候 空needle 在 haystack中是0, 其他情况 -1
// l l
// 0 -1 -1
// h 0 -1 -1
// e 0 -1 -1
// l 0 2 -1
// l 0 3 2
// o 0 -1 -1
// //by exe
// 0 -1 -1
// 0 -1 -1
// 0 -1 -1
// 0 2 -1
// 0 3 2
// 0 -1 -1
//* 关键是needle[0] 首次出现位置移到要初始化为i-1
//offset 法 , needle[j] hay[i] ==> dp[i+1][j+1]
//如果不用二维dp 则必须从右向左遍历
std::vector<std::vector<int>> dp(haystack.size()+1, std::vector<int>(needle.size()+1,0 ));
for(int j=1;j<=needle.size();j++) dp[0][j] =-1;
for(int i=0;i<haystack.size();i++)
{
#if 0
//从左到右遍历 会超时
for(int j=0;j< needle.size();j++ )
{
if(haystack[i] == needle[j] )
{
if(j>0) dp[i+1][j+1] = dp[i][j];
else dp[i+1][j+1] = i;
}else
{
dp[i+1][j+1] = -1;
}
//here detect
if(j== needle.size() -1 && dp[i+1][j+1] != -1 ) return dp[i+1][j+1];
}
#endif
// //从右到左遍历会超时
for(int j=needle.size()-1;j>=0;j-- )
{
if(haystack[i] == needle[j] )
{
if(j>0) dp[i+1][j+1] = dp[i][j];
else dp[i+1][j+1] = i;
}else
{
dp[i+1][j+1] = -1;
}
//here detect
if(j== needle.size() -1 && dp[i+1][j+1] != -1 ) return dp[i+1][j+1];
}
}
// for(auto vec: dp)
// {
// for(auto t: vec ) std::cout << t << " ";
// std::cout << std::endl;
// }
if(haystack.empty() || needle.empty() ) return dp[haystack.size()][needle.size()];
return -1;
}
};
题目描述
- 实现 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 仅由小写英文字符组成