1 KMP算法
已经将个人的理解全部写入以下链接之中了,需要注意的是这篇文章从头到尾采用的前缀表右移的方法计算next数组:
KMP算法解析
另一种前缀表全部-1的计算方法和上述方法异曲同工,但细节上会有区别。
2 字符串匹配
LeetCode:找出字符串中第一个匹配项的下标
典中典中典的问题,就是KMP算法应用场景,无需多说,直接上代码,详细解析看上面。
class Solution {
public:
int strStr(string haystack, string needle) {
//KMP算法
int h_size=haystack.size();
int n_size=needle.size();
int next[n_size];
int i=0;
int j=0;
//初始化next[0]与k
//k代表next[i],needle_i的最长相同前缀的长度
next[0]=-1;
int k=-1;
while(i<n_size-1)
{
//如果k==-1,代表着在已有的前缀表中不存在needle[i]==needle[k]
//那么意味着needle[i]无法与needle进行匹配,那么直接将字符串needle的头移动到i+1
//此时,needle[i+1]=0
//另外,因为needle[i]=k,因此0~k-1和i-k~i-1一致
//若needle[i]==needle[k],则0~k和i-k~i一致,为新的最长相等前缀
//此时needle[i+1]=k+1
if(k==-1||needle[i]==needle[k])
{
next[i+1]=k+1;
++i;
++k;
}
//needle[i]!=needle[k]时,需要缩短前缀长度
//寄希望于needle[next[k]],因为next[k]的最大相等长度也是needle[i]的部分相等长度
//如果needle[next[k]]==needle[i],就相当于找到一个新的略短但也是最大的相等长度
else
k=next[k];
}
//查询
i=0;
while(i<h_size && j<n_size)
{
if(j==-1||haystack[i]==needle[j])
{
++i;
++j;
}
else
{
j=next[j];
}
}
if(j==n_size)return i-n_size;
return -1;
}
};
3 重复的子字符串
LeetCode:重复的子字符串
这题也可以采用KMP算法解决,需要注意的是,如果采用前序表右移的方法生成next数组,需要对最末尾的元素和单字符字符串的情况进行处理。
其思路是,若是重复的子字符串,最小重复子字符串必定是最大相同前后缀与字符串之间的差值,即[字符串]=[最小子字符串][最大相同前后缀],那么利用求余就可以判断出字符串是否为重复的子字符串。
class Solution {
public:
bool repeatedSubstringPattern(string s) {
int size=s.size();
if(size<2)return false;
int next[size];
int i=0;
int j=-1;
next[0]=-1;
while(i<size-1)
{
if(j==-1 || s[i]==s[j])
{
next[i+1]=j+1;
++i;
++j;
}
else
j=next[j];
}
int max_len=next[size-1]+1;
int min_len=size-max_len;
return size%min_len==0 && s[size-1]==s[min_len-1];
}
};
4 总结
今天主要是学习了KMP算法,还手撕了半天,晚上还将前缀表后移1位和前缀表全部-1两种next数组生成方法误以为成一种,导致在第二道题中怀疑人生两个小时,真的可笑。
另外今天还训练了W-GAN,虽然train起来之后才想起,应该要把之前的2次DCGAN和1次WGAN的结果记录一下并且写篇博客的,算了,直接拖到明天吧。
——2023.2.22