https://gitee.com/fakerlove/Data-Structure
4. 串
4.1 模式匹配
1. 暴力算法 bf
从左到右一个个匹配,如果这个过程中有某个字符不匹配,就跳回去,将模式串向右移动一位。这有什么难的?
匹配不成功,i回溯到开始,j 回溯到子串的开头
匹配不成功,i 往后走
时间复杂度O(m*n)
2. KMP 算法
利用已经部分匹配这个有效信息,保持i指针不回溯,通过修改j指针,让模式串尽量地移动到有效的位置
时间复杂度O(m+n)
前缀,后缀,部分匹配值
- 前缀:除去最后一个字符外,字符串的所有头部子串
- 后缀:除去第一个字符外,字符串的所有头部子串
- 部分匹配值:字符串的前缀和后缀最长相等的前后缀长度
字符串 | 部分匹配值 | 前缀 | 后缀 |
---|---|---|---|
a | 0 (空集 空集) | 空集 | 空集 |
ab | 0 {a} {b} | a | b |
aba | 1 {a,ab} {ba,a} | ab a | ba a |
abab | 2 {a,ab,aba} {b,ab,bab} | a ab aba | b ab bab |
ababa | 3 {a,ab,aba,abab} {a,ba,aba,baba} | a ab aba abab | a ba aba baba |
ababc | 0 {a,ab,aba,abab} {c,bc,abc,babc} | a,ab,aba,abab | c,bc,abc,babc |
sssss | 4 | s,ss,sss,ssss | s,ss,sss,ssss |
abca | 1 {a,ab,abc} {a,ca,bca} | a,ab,abc | a,ca,bca |
next 数组 (子串回溯的位置)
-
匹配的过程 KMP 算法的过程
移动主串情况
-
如果是 j== -1 ,表示就是第一个字符匹配失败,第一个元素匹配失败,不需要移动子串,只需要移动主串
-
或者 字符串匹配成功
-
不移动主串的情况
- 匹配失败,子串回溯
- 右移的数字 = 已经匹配的字符数-对应的部分匹配值 j=next[j]+1
代码
int kmp(char str[],char temp[])//这个是查找
{
int i = 0;//这个是主字符串的位置
int j = 0;//这个是子字符串的位置
int length1 = strlen(str);
int length2 = strlen(temp);
while (i<length1&&j<length2)
{
if (j==-1||str[i] == temp[j]) {
i++;
j++;
}
else {
j = next[j];
}
}
if (j==length2) {
return i - j;
}
return -1;
}
- 代码 next 数组怎么求
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int next[1001];//这个是next数组
//函数声明
void getNext(char str[]);
int KMP(char str[],char temp[]);
int main()
{
int i = 0;
char str[1001];//这个是主字符串
char temp[1001];//这个是用来匹配的字符串
int length = 0;//这个是主字符串的长度。
int result = -1;
printf("请输入第一个字符串\n");
gets(str);//在vs中用scanf_s();
printf("请输入第二个字符串\n");
gets(temp);//在vs中用scanf_s();
getNext(str);//建立next数组
result = KMP(str,temp);//这个是获取结果
printf("\n");
if (result <= 0) {
printf("没有找到匹配的字符串");
}
else {
printf("结果在主字符串的位置为 %d",result+1);
}
// system("pause");
return 0;
}
void getNext(char str[])//next数组的建立,这个是关键
{
// 初始化
int i=0,j = -1;
int length1 = strlen(str);
// 第一个不匹配的话,是主串开始往后加一
next[0] = -1;
while (i < length1) {
// -1 表示是第一个字符串,第一个字符串不需要赋值,因为肯定是-1 ,
// 还有一种情况就是
if ( j== -1 || str[j] == str[i]) {
i++;
j++;
next[i] = j;
}
else {
j = next[j];
}
}
}
int kmp(char str[],char temp[])//这个是查找
{
int i = 0;//这个是主字符串的位置
int j = 0;//这个是子字符串的位置
int length1 = strlen(str);
int length2 = strlen(temp);
while (i<length1&&j<length2)
{
if (j==-1||str[i] == temp[j]) {
i++;
j++;
}
else {
j = next[j];
}
}
if (j==length2) {
return i - j;
}
return -1;
}