题目:28. 实现 strStr()
文章链接:代码随想录
视频链接:LeetCode:实现strStr
题目链接:力扣题目链接
详解:KMP:主要应用于字符串匹配,当出现字符串不匹配是,可以知道一部分之前已经匹配的文本内容,利用该信息避免从头再做匹配
当匹配到字符串'f'不匹配时,退回到下标为2的位置开始匹配,不用重新从小标为0的位置开始匹配
前缀:不包含末尾元素的顺序组成,eg: aabaaf的前缀为a、aa、aab、aaba、aabaa
后缀:不包含首元素的顺序组成,eg: aabaaf的后缀为f、af、aaf、baaf、abaaf
前缀表:记录了模式串与主串(文本串)不匹配的时候,模式串应该从哪里开始重新匹配,记录小标i之前(包括i)的字符串中,有多大长度的相同前缀后缀
class Solution {
public:void getNext(vector<int>&next, const string& s) {// 初始化前缀表next[0] = 0;int j = 0; // 初始化前缀末尾for (int i = 1; i < s.size(); i++) {// 前缀后缀不相等的情况while (j > 0 && s[j] != s[i]) { // 要确保j-1>=0,所以对j进行一个限制j = next[j - 1]; //找前一位对应的回退位置}// 前后缀相等的情况if (s[j] == s[i]) {j++; // 如果相同进行加1}next[i] = j; // 赋值前缀表}
}
// 实现 strStr()
int strStr(string haystack, string needle) {// needle为需要匹配的字符串,计算该字符串的前缀表if (needle.size() == 0) return 0;vector<int>next(needle.size()); //初始化getNext(next, needle); //获得前缀表// 开始进行匹配,跟获得前缀表差不多int j = 0;for (int i = 0; i < haystack.size(); i++) { //不同点在于,两个字符串进行匹配时从0开始// 不匹配的情况while (j > 0 && needle[j] != haystack[i]) {j = next[j - 1]; // 回退}if (needle[j] == haystack[i]) {j++;}// 这里与getNext不用,不用构建前缀表,如果满足,直接返回if (j == needle.size()) {// 当j == needle.size(),i还没++return (i - needle.size()+1);}}return -1;
}
};
题目:459.重复的子字符串
文章链接:代码随想录
视频链接:LeetCode:459.重复的子字符串
题目链接:力扣题目链接
图释:
void getNext(vector<int>&next, const string& s) {// 初始化前缀表next[0] = 0;int j = 0; // 初始化前缀末尾for (int i = 1; i < s.size(); i++) {// 前缀后缀不相等的情况while (j > 0 && s[j] != s[i]) { // 要确保j-1>=0,所以对j进行一个限制j = next[j - 1]; //找前一位对应的回退位置}// 前后缀相等的情况if (s[j] == s[i]) {j++; // 如果相同进行加1}next[i] = j; // 赋值前缀表}
}
// 重复的子字符串
bool repeatedSubstringPattern(string s) {// 通过计算最大前缀表来得到vector<int> next(s.size());getNext(next, s);int len = s.size();if (next[len-1]!= 0 // 如果等于的话,至少说明最后一个不能重复&& len % (len - next[len-1]) // 最长相同前后缀的长度== 0) {return true;}return false;
}