- 找出字符串中第一个匹配项的下标
- 重复的子字符串
28. 找出字符串中第一个匹配项的下标
第一想法
KMP的典型题目,回顾一下。
解题思路
- -1开始
next[]
数组保存的就是 前缀和后缀 相等的最长距离- 比如现在是算第i个字母的,则在[0,i)和(0, i]范围中寻找
- 第一步:找needle串的
next[]
数组,aabaaf
对应的是-1 0 -1 0 -1 0
实际上长度都要+1,所以比较都要比较的是needle[i] ? needle[j + 1]
,当然第一个字符一定是-1,所以从1开始遍历。 - 如果不相等就要回退,
aab
此时i = 2, j =0
对应的是b a
所以不想等,应该回退的是第一个a
的next[]
数组,所以是j - 如果相等 j++,直到遍历完
- 第二步:遍历haystack,比较needle串。此时haystack就要从0开始遍历,如果不相等还是要回退,相等的话
j++
,需要判断什么时候找到。
- 1开始
- 第一步:同上,
aabaaf
对应的是0 1 0 1 2 1
,比较的是needle[i]和needle[j]
,第一个字符一定是0,所以从1开始遍历。 - 不相等就回退,
aab
回退到第一个a,所以是j - 1
- 第二步:遍历haystack,比较needle串。此时haystack就要从0开始遍历,如果不相等还是要回退,相等的话
j++
,需要判断什么时候找到。
代码
- -1开始
class Solution {
public:
int strStr(string haystack, string needle) {
int j = -1;
vector<int> next(needle.size(), -1);
for (int i = 1; i < needle.size(); i ++){
while (j >= 0 && needle[i] != needle[j + 1]) j = next[j];
if (needle[i] == needle[j + 1]) j ++;
next[i] = j;
// cout << next[i] << endl;
}
j = -1;
for (int i = 0; i < haystack.size(); i ++){
while (j >= 0 && haystack[i] != needle[j + 1]) j = next[j];
if (haystack[i] == needle[j + 1]) j ++;
if (j == needle.size() - 1) return i - j;
}
return -1;
}
};
- 0开始
class Solution {
public:
int strStr(string haystack, string needle) {
int j = 0;
vector<int> next(needle.size(), 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;
// cout << next[i] << endl;
}
j = 0;
for (int i = 0; i < haystack.size(); i ++){
while (j > 0 && haystack[i] != needle[j]) j = next[j - 1];
if (haystack[i] == needle[j]) j ++;
if (j == needle.size()) return i - j + 1;
}
return -1;
}
};
459. 重复的子字符串
解题思路
abcabcabcabc
重复4次,它的最后一位next数组一定是重复3次的,因为最长公共前后缀比较都少一位,所以当字符串长度-next数组最后一位公共长度,一定是重复的字串长度,所以只要字符串长度可以整除无余数,就没问题。
注意,当最后一位0的时候要特判。
代码
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int j = -1;
vector<int> next(s.size(), -1);
for (int i = 1; i < s.size(); i ++){
while (j >= 0 && s[i] != s[j + 1]) j = next[j];
if (s[i] == s[j + 1]) j ++;
next[i] = j;
cout << next[i] << endl;
}
int m = s.size();
int n = next[s.size() - 1] + 1;
if (n == 0) return false;
if (m % (m - n) == 0) return true;
return false;
}
};
字符串总结
字符串和数组的关系
string vector
双指针
- 反转 k 2k 单词空格句子 移除特定元素
KMP
双指针
- 链表:调换方向、是否有环
- 字符串:移除元素
- 数组:移除元素
- 三数之和:
f[i] == f[i -1]
的时候要continue