KMP算法是测试智商的好办法,事实证明我智商捉急。
自己看思路写了好久才写出的代码,没有优化。
一个同学说我写的abcabaa最后一个出错了,由于没有照顾到前面有一堆相同然后有一个不同的情况。已经解决好了。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void get_next(char *t, int len, int next[]) {
next[0] = -1;
int k = 0;
int isHaveSameStrAndOneDiffChar = 0;
for (int j = 1; j < len; ) {
if (k == 0&& isHaveSameStrAndOneDiffChar==0) {
if (t[j] == t[k]) {
next[j] = k;
j++;
k++;
}
else {
next[j] = 0;
j++;
}
}
else {
if (isHaveSameStrAndOneDiffChar == 0) {
if (t[j - 1] == t[k - 1] && t[j] == t[k]) {
next[j] = k;
j++;
k++;
}
else if (t[j - 1] == t[k - 1] && t[j] != t[k]) {
next[j] = k;
j++;
k = next[k];
isHaveSameStrAndOneDiffChar = 1;
}
}
else if(isHaveSameStrAndOneDiffChar == 1){
if (t[j - 1] == t[k]) {
k++;
isHaveSameStrAndOneDiffChar = 0;
}
else {
k = next[k];
if (k == -1) {
k++;
isHaveSameStrAndOneDiffChar = 0;
}
}
}
}
}
for (int i = 0; i < len; i++) {
printf("%d ", next[i]);
}
printf("\n");
}
int kmp(char *s, char *t) {
int s_len = strlen(s);
int t_len = strlen(t);
int *next = malloc(t_len * sizeof(int));
get_next(t, t_len, next);
int i = 0, j = 0;
while (i <= s_len - t_len) {
int k = i;
int j = 0;
while (k < s_len && j < t_len) {
if (j == -1) {
i = k + 1;
break;
}
else if (s[k] == t[j]) {
k++;
j++;
}
else
j = next[j];
}
if (j == t_len)
return k-t_len;
}
return -1;
}
int main() {
char *s = "abcaabbabcabdacaabcaabbabcabaac";
char *t = "abcaabbabcabaac";
printf("%s", s+kmp(s, t));
}
时隔半年,来一个优化后注释了的版本
#include<iostream>
void get_next(char *t, int t_len, int *next)
{
next[0] = -1;//第0个不相同,只能前进,主指针只能前进
//j,k代表包括字符j-1和k-1前的相同,求字符j和k不相同时的next[j]
int j = 0;//主指针,计算从1开始,由于先++,所以设为0
int k = -1;//开始设为-1是因为
while (j < t_len)
{
if ((k == -1) || (t[j] == t[k]))//-1情况代表连模式串第一个字符也不相同,所以下一个字符从头比较,next为0,从头比较,这里合并了两种情况
{
++j;
++k;
next[j] = k;//k-1个前面是相同的,所以直接比较k
}
else
{
k = next[k];//当前字符不相同,求前面的相同的下一个字符
}
}
for (int i = 0; i < t_len; i++)
{
printf("next[%d]=%d\n",i+1, next[i]+1);
}
}
int kmp(char *s, char *t, int s_len, int t_len)
{
int next[400];
int i = 0;//主指针
int j = 0;//模式指针,一开始当然是从0开始比较
get_next(t, t_len, next);
while (i < s_len && j < t_len)
{
if (j == -1 || (s[i] == t[j]))//-1代表连第一个也不相同,前进,从头比较。
{
i++;
j++;
}
else
j = next[j];//
}
if (j == t_len)
{
// printf("%d %d test\n", i, t_len);
return i - t_len;
}
else
return -1;
}
int main()
{
char s[2000];
char t[400];
scanf("%s", s);
scanf("%s", t);
printf("模式在文本中的位置是%d\n", kmp(s, t,strlen(s),strlen(t))+1);
}