LeetCode 28 找出字符串中第一个匹配项的下标
题目链接:28. 找出字符串中第一个匹配项的下标
做题情况:虽然是二刷代码随想录,但是KMP算法自己总体思路还是那么混乱以及代码实现也无从下手,继续看卡哥视频和代码随想录书相关部分后,对此算法有了更深的理解,主要在以下几点:① 理解前缀表,也就是next数组怎么回事 ② next数组求解的具体实现 ③咋样使用next数组做匹配以及具体实现,其中next数组求解主要是以下三点:① 初始化next数组 ② 处理前后缀不相同的情况 ③处理前后缀相同的情况,然后自己对卡哥所给的代码重新抄写了一遍,后面还有好好复习,以及自己自己独立去实现,下面是卡哥的代码:
//前缀表统一减一的代码实现
class Solution {
public:
void getNext(int* next, const string& s){
int j=-1;
next[0]=j;
for(int i=1;i<s.size();i++){//注意i从1开始
while(j>=0&&s[i]!=s[j+1]){//前后缀不相同
j=next[j];
}
if(s[i]==s[j+1]){//找到相同的前后缀
j++;
}
next[i]=j;//将j(前缀的长度)赋值给next[i]
}
}
int strStr(string haystack, string needle) {
if(needle.size()==0){
return 0;
}
int next[needle.size()];
getNext(next, needle);
int j=-1;//next数组中记录的起始位置为-1
for(int i=0;i<haystack.size();i++){//注意i就从0开始
while(j>=0&&haystack[i]!=needle[j+1]){//不匹配
j=next[j];//j寻找之前的匹配位置
}
if(haystack[i]==needle[j+1]){//匹配,j和i同时向后移动
j++;//i的增加逻辑再for循环中
}
if(j==(needle.size()-1)){//文本串s中出现了模式串t
return (i-needle.size()+1);
}
}
return -1;
}
};
//前缀表不减1来构建next数组
class Solution {
public:
void getNext(int* next, const string& s){
int j=0;
next[0]=j;
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) {
if(needle.size()==0){
return 0;
}
int next[needle.size()];
getNext(next, needle);
int j=0;//next数组中记录的起始位置为-1
for(int i=0;i<haystack.size();i++){//注意i就从0开始
while(j>0&&haystack[i]!=needle[j]){//不匹配
j=next[j-1];//j寻找之前的匹配位置
}
if(haystack[i]==needle[j]){//匹配,j和i同时向后移动
j++;//i的增加逻辑再for循环中
}
if(j==(needle.size())){//文本串s中出现了模式串t
return (i-needle.size()+1);
}
}
return -1;
}
};
构造next数组从初始化、相同情况和不相同情况(特别其中while循环)的逻辑理解就行
LeetCode 459 重复的子字符串
题目链接:459. 重复的子字符串
做题情况:毫无头绪的一道题目,看完卡哥视频和代码随想录书相关部分后,才知道本题有多种解法:① 暴力解法(这种解法理解思路即可) ② 移动匹配(自己理解起来比较别扭,我觉得凭我现有的知识记住和温习即可) ③ KMP方法(感觉很巧妙的一种的方法,原来next数组还可以这样用),自己又把卡哥给的代码给抄了一遍,具体如下:
//移动匹配方法
class Solution {
public:
bool repeatedSubstringPattern(string s) {
string t=s+s;
t.erase(t.begin());
t.erase(t.end()-1);
if(t.find(s)!=std::string::npos)return true;
return false;
}
};
//前缀表减1来构建next数组
class Solution {
public:
void getNext(int* next, const string& s){
int j=-1;
next[0]=-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;
}
}
bool repeatedSubstringPattern(string s) {
if(s.size()==0){
return false;
}
int next[s.size()];
getNext(next, s);
int len=s.size();
if(next[len-1]!=-1&&len%(len-(next[len-1]+1))==0){
return true;
}
return false;
}
};
//前缀表不减1来构建next数组
class Solution {
public:
void getNext(int* next, const string& s){
int j=0;
next[0]=j;
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) {
if(s.size()==0){
return false;
}
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;
}
};
虽然是二刷,但是今天大部分都是在学习卡哥的讲解和抄代码,独立完成还是那么难,呜呜
字符串章节总结
具体总结见卡哥总结
我觉得这章节这些题目得过一段时间又得多刷几遍,多思考总结,尽量自己独立快速完成,有太多技巧且代码实现能力要求也高
双指针回顾
具体总结见卡哥总结
这些双指针题目和字符串题目一样的建议
今天花了五个小时左右来完成任务,还是有点懵,后面多抽些时间来看看和回顾
贵在坚持,加油,共勉