Brute Force
int StrBruteForce(LinkString* s, LinkString* t)
{
LinkString* p = s;
LinkString* p1;
LinkString* q ;
while (p->next)
{
q = t->next;
p = p->next;
p1 = p;
while (p1 && q && p1->data == q->data)
{
p1 = p1->next;
q = q->next;
}
if (!q )
return true;
if (!p1)
return false;
}
return false;
}
KMP
-
KMP算法: 每次失配,S串的索引i不动,P串的索引j定位到某个数。T(n)=O(n+m),时间效率明显提高
-
这里关键是求一个模式串的Next数组
- 我们先把模式串标出序号:
- 接着把模式串所有前缀依次列出来
- 接下来把每一个子串相等的前缀和后缀的最大长度求出,举个例子”abaab“
- 观察子串,前后缀ab相同,因此返回2
5.依次类推,我们可以得到每一个子串对应的一组序列
当时这组数据并不是所要求的next数组,可以将其称为部分匹配值表,相应c代码如下
//获得部分匹配值表
void GetIndexStr(SqString* s,int next [])
{
int i = 1;
int j = 0;
next[0] = 0;
while (i < s->length)
{
if (s->data[i] == s->data[j])
next[i++] = (j++) + 1;
else if ( j ==0 && s->data[i] != s->data[j])
next[i++] = 0;
else
j = next[j - 1];
}
}
- 接着我们可以得到 首字为 -1 版本的next数组
- 将上述得到的序列向右平移1位(去掉最后一个数),开头补上 -1 即可
相应c代码如下
//获得next数组 :相当于部分匹配值表右移1位,前插 - 1
void GetNextArr(SqString* s, int next[])
{
int i = 0 ;
int j = -1 ;
next[0] = -1;
while (i < s->length - 1)
{
if (j == -1 || s->data[i] == s->data[j])
next[++i] =++ j ;
else j = next[j];
}
}
- 要想得到严蔚敏版本的,即将上述序列全部元素+1即可,代码如下:
void GetNextArrAdd1(SqString* s, int next[])
{
int i = 0;
int j = -1;
next[0] = j+1;
while (i < s->length - 1)
{
if (j == -1 || s->data[i] == s->data[j])
next[++i] = ++j +1;
else
j = next[j] - 1;
}
}
- 获取到next数组之后,接下来便是KMP算法的主流程
int KMPStr(SqString* s, SqString* t)
{
int next[MAX_SIZE];
int i = 0;
int j = 0;
GetNextArr(t,next);
while (i < s->length && j<t->length)
{
if (j == -1 || s->data[i] == t->data[j])
{
i++;
j++;
}
else j = next[j];
}
if (j >= t->length)
return (i - t->length);
else
return -1;
}
改进KMP
- 按前面的定义可以得到,next[j] = k
- 若Tj=Tk,那么当Tj和Si不匹配时,也没必要将Si和Tk进行匹配
- 因此直接将Si和T(next(k))进行匹配
void GetNextValArr(SqString* s, int nextVal[])
{
int i = 0;
int j = -1;
nextVal[0] = -1;
while (i < s->length - 1)
{
if (j == -1 || s->data[i] == s->data[j])
{
i++;
j++;
if (s->data[i] != s->data[j])
nextVal[i] = j;
else nextVal[i] = nextVal[j];
}
else
j = nextVal[j];
}
}