提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、KMP算法
看了两遍视频终于看懂了!
1.解决的问题
解决字符串匹配的问题(文本串中是否出现模式串 )。暴力法的时间复杂度为O(m*n)。
文本串:aabaabaaf
模式串:aabaaf
从头开始匹配,在第5位f和b不匹配,kmp算法移动到模式串的第二位b继续匹配。(因为4、5位的aa和1、2位的aa相同)
2.前缀表
以模式串aabaaf为例,前缀有:a、aa、aab、aaba、aabaa;后缀有:f、af、aaf、baaf、abaaf。前缀表保存最长相等前后缀的长度。
3.前缀表使用方法
找到不匹配的位置,找到与其相等的前缀开始匹配,即使用前缀表回退到相等前缀的位置。
4.前缀表next数组的实现方法
指针i指向后缀末尾;指针j指向前缀末尾,j也表示字串的最长相等前后缀的长度。
void getNext(int* next, const string s) {
int j = 0;
next[j] = 0;
for (int i = 1; i < s.size(); i ++) {
while (j > 0 && s[i] != s[j]) {
j = next[j-1];
}
if (s[i] == s[j]) {
j ++;
}
next[i] = j;
}
}
二、28找出字符串中第一个匹配项的下标
class Solution {
public:
void getNext(int* next, const string s) {
int j = 0;
next[j] = 0;
for (int i = 1; i < s.size(); i ++) {
while (j > 0 && s[i] != s[j]) {
j = next[j-1];
}
if (s[i] == s[j]) {
j ++;
}
next[i] = j;
}
}
int strStr(string haystack, string needle) {
int next[needle.size()];
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.size(); i++) {
if (haystack[i] == needle[j]) {
j ++;
}
else {
if (j > 0) {
j = next[j-1];
i --;
}
}
if (j == needle.size()) {
return i - needle.size() + 1;
}
}
return -1;
}
};
三、459重复的子字符串
自己先写了个O(n2)的
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int n = s.size();
for (int i = 1; i <= n / 2; i ++) {
if (n % i != 0) {
continue;
}
int j;
for (j = i; j < n; j ++) {
if (s[j] != s[j-i]) {
break;
}
}
if (j == n) return true;
}
return false;
}
};
然后又试着写了下KMP算法版本,改了好多遍,靠badcase堆起来的。。感觉自己模版背的溜溜的,但是似懂非懂
class Solution {
public:
void getNext(int* next, const string s) {
int j = 0;
next[j] = 0;
for (int i = 1; i < s.size(); i ++) {
while (j > 0 && s[i] != s[j]) {
j = next[j-1];
}
if (s[i] == s[j]) {
j ++;
}
next[i] = j;
}
}
bool repeatedSubstringPattern(string s) {
int n = s.size();
int next[n];
getNext(next, s);
int count = next[n-1];
if (count == 0) return false;
for (int i = count; i < n; i ++) {
if (s[i] != s[i-count]) return false;
}
return true;
}
};
还有一种思路就是子串的长度一定是总长度的公因数。比方说长度为5的字符串就一定不会由子串组成。
字符串总结
字符串是若干字符组成的有限序列,是一个字符数组。overover!过段时间再来看看kmp