名词解释:
主串:比如:s1=“goodgoogle"
模式串:在主串中想要找的子串,
s2=“google”,既是在s1中找s2
普通的暴力做法:
有两种情况:
匹配成功:i , j都向后移动,继续比较
匹配失败:i回到最上次的下一个位置,j回到模式串的最开始
代码如下:
int find_sub_string(string s, string t)
{
int i = 0, j = 0; //初始化两个指针
while(i<s.size() && j<t.size()){
if(s[i] == t[j]){
//sucess:
i++; //如果两个指针指向的字符相等
j++; //则将两个指针向后移动
}
else{
//failure:
i = i - j + 1; //匹配失败,i退回到上次匹配首位,的下一位
//j也代表着移动位置,i-j既是回到了上次的开始,+1代表下次的开始
j = 0; //j退回到子串首位
}
}
if(j>=t.size()){
//j走到子串末尾说明匹配成功
return i - j; //匹配成功返回主串中子串出现的第一位
}
else
return -1; //匹配失败,返回-1
}
两种算法我认为的不同之处:
暴力算法:一出错 i , j 都要回溯
KMP算法:只回溯 j,主串i 不回溯(也就是主串只向前,模式串反复横跳)
KMP算法
名词解释
字符串 abcdab
前缀的集合:{a,ab,abc,abcd,abcda}
后缀的集合:{b,ab,dab,cdab,bcdab}
那么最长相等前后缀不就是ab.
看这两个视频就够了:
基础部分【天勤考研】KMP算法易懂版
基础
步骤:(看不懂不要紧)
(1)比较,直至不匹配
(2)找最长前后缀
(3) i 不动,j 回溯(如果有公共部分,保证 i 和 j 前面相同,这样可以省下部分的比较时间,没有公共前缀,j 就回到最开始 1 位置处)
(4)回到(1)
第一次:
(1)比较,直至不匹配
如图:绿色代表匹配,红色的叉代表不匹配
这个时候我们主串的i就不动了,
动模式串
(2)找最长前后缀
AB为最长前后缀
此时 i 和 j 都在6,指向不匹配的位置
(3)i 不动,j 回溯
i 不动
AB为最长前后缀,那么就让AB移动到下一个AB对齐(也就是j回退到位置3,因为公共前缀(他两个一样的)移动到了匹配的下一个
此时就是i =6 ,j = 3, i 和 j 比较
第二次:
(1)比较,直至不匹配
(2)找最长前后缀
A为最长前后缀
(3)i 不动,j 回溯
A为最长前后缀,那么就让A移动到下一个A对齐
第三次:
(1)比较,直至不匹配
(2)找最长前后缀
AB里面,没有
(3)i 不动,j 回溯
j 移动到模式串最开始处
等等…
next代码讲解
void Get_Next(char *s,int length,int *Next)
{
Next[1] = 0