求两个字符串的最长公共子串(初学者适用)
何为公共子串?
即两个字符串中相等且连续的子串。
例如:串“abcde”和串“gabfcde”中公共子串有ab”和“cde”两个。
何为最长公共子串呢?
即在上述“公共子串”的定义中加上最长二字, 上面例子中“cde”便是最长公共子串。
基本算法思想
大致思路
假设有串str1和串str2。挨个找出str1和str2中所有的公共子串,在寻找过程中只记录下长度最长的公共子串。
-
先固定其中一个字符串(此处将str1固定),取其第一个字符str1[0],查找str1和str2中有没有以该字符开头的公共子串:
将str[0]与str2中的字符挨个比较,若遇到相等的,再接着比较str1和str2中相等字符的下一个位置,直至遇到下一对不相等的字符,即完成一个公共子串的搜寻。例如:
若该公共子串的长度大于之前搜寻到的公共子串长度,则将原有的覆盖掉(始终保留长度最大的公共子串),之后继续查找,将str1[0]与str2中的剩余字符逐一比较。
-
之后再依次取出str1中的第2个、第3个…第n个字符,重复上述操作,当str1中的所有字符均取出和str2中的字符遍历比较后,此时所记录下来的公共子串即为所求的最长公共子串。
实现代码
这是我个人的思想,可能理解起来有点麻烦,但还是想把它记录下来
`#include<stdio.h>
#include<string.h>
typedef struct //设置一个栈来记录下每次找到的公共子串
{
int num;
char str[100];
}Stack;
void Init(Stack &s)//在查找完一个公共子串后,需要将栈初始化,以存放下一个公共子串的信息
{
s.num=0;
for(int i=0;i<100;++i)
s.str[i]=0;
}
char s[100]={0};//存放最长公共子串
void find(Stack s1,char *str1,char *str2)
{
for(int i=0;i<strlen(str1);++i)
{
int k=i,j=0;//k是i的替身,防止i变化,j用于str2中的字符
while(j<strlen(str2))
{
if(str1[k]==str2[j])//相等时,将相等字符记录下来,并移动k和i
{
s1.str[(s1.num)++]=str1[k];
++k;++j;
}
else
{
if(strlen(s1.str)>strlen(s))//不相等时,若已经找到一个公共子串,则判断该公共子串与原有公共子串的长度大小,保留长度较大者
{
for(t=0;t<strlen(s1.str);++t)
s[t]=s1.str[t];
}
if(strlen(s1.str))//如果前面存在公共子串,说明k已经不是str1中取出的第i个字符了,在进行下一次比较前,需将其置为i
k=i;
else //否则就一直挨个与str2中的字符进行比较
++j;
Init(s1);//下一次查找前,对其初始化(清空掉上一次的公共子串信息)
}
}
}
}
int main()
{
Stack s1;Init(s1);
char str1[]="abcdkkk";
char str2[]="baabcdadabc";
find(s1,str1,str2);
printf("%d\n",strlen(s));
puts(s);
return 0;
}