今天去面试,面试官出了一道题,求两个字符串的最大公共子串(Longest Common Substring),一听起来不是很难,但让我在纸上写着写着就迷糊了。回来特地网搜了一下。面试
下面经过两种方法来求两个字符串的最大连续公共子串。数组
方法1:暴力解法code
将字符串s1和s2分别写在两把直尺上面,而后将s1固定,s2的头部和s1的尾部对齐,而后逐渐移动直尺s2,比较重叠部分的字符串中的公共子串的长度,直到直尺s2移动到s1的头部。在这个过程当中求得的最大长度就是s一、s2最大子串的长度。内存
#include
#include
#include
char* longest_common_substring(char *str1,char *str2)
{
int str1len = strlen(str1);
int str2len = strlen(str2);
int i,j,index,max=0,num=0;
int start;
//将两个字符串看作两个直尺,固定一个直尺,另一个从头至尾开始移动,逐一与固定的直尺比较值。
for(i = 0; i < str1len; i++)
{
for(j = 0; j < str2len; j++)
{
//这里的start一、start2是比较关键的
int start1=i;
int start2=j;
while((start1 <= str1len-1) && (start2 <= str2len-1) && (str1[start1++] == str2[start2++]))
num++;
if(num > max)//若是num是当前最大匹配的个数,则赋给max,而且在start记下str1最长匹配开始的位置
{
max=num;
start=i;
}
num=0;//若是num不是当前最大的,则赋为0值继续循环
}
}
char *str=(char *)malloc(max + 1);
strncpy(str,str1 + start,max);//从字符串str1的start位置开始,拷贝max个字符到str中,这就是咱们找出的最大子串
str[max] = '\0';
printf("最长公共连续子串的长度为:%d\n",max);
return str;
}
int main()
{
char str1[1000],str2[1000];
printf("请输入第一个字符串:");
gets(str1);
printf("请输入第二个字符串:");
gets(str2);
char *str= longest_common_substring(str1,str2);
printf("%s\n",str);
free(str); //记得要free,不然形成内存泄露
system("pause");
return 0;
}
方法2:动态规划解法字符串
主要是定义了一个二维数组,这个数组c用来保存str1中每一个字符向前能与str2中的字符匹配的个数。每次会将最大的匹配个数保存到max变量中,而且记录拥有max的字符在原字符串中的位置。get
当str1[i] == str2[j]时,子序列长度c[i][j] = c[i - 1][j - 1] + 1;只是当str1[i] != str2[j]时,c[i][j]长度要为0,而不是max{c[i - 1][j], c[i][j - 1]}。string
/**
找出两个字符串的最长公共连续子串的长度
**/
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int longest_common_substring(char *str1, char *str2)
{
int i,j,k,len1,len2,max,x,y;
len1 = strlen(str1);
len2 = strlen(str2);
int **c = new int*[len1+1];
for(i = 0; i < len1+1; i++)
c[i] = new int[len2+1];
for(i = 0; i < len1+1; i++)
c[i][0]=0; //第0列都初始化为0
for(j = 0; j < len2+1; j++)
c[0][j]=0; //第0行都初始化为0
max = -1;
for(i = 1 ; i < len1+1 ; i++)
{
for(j = 1; j < len2+1; j++)
{
if(str1[i-1]==str2[j-1]) //只须要跟左上方的c[i-1][j-1]比较就能够了
c[i][j]=c[i-1][j-1]+1;
else //不连续的时候还要跟左边的c[i][j-1]、上边的c[i-1][j]值比较,这里不须要
c[i][j]=0;
if(c[i][j]>max)
{
max=c[i][j];
x=i;
y=j;
}
}
}
//输出公共子串
char s[1000];
k=max;
i=x-1,j=y-1;
s[k--]='\0';
while(i>=0 && j>=0)
{
if(str1[i]==str2[j])
{
s[k--]=str1[i];
i--;
j--;
}
else //只要有一个不相等,就说明相等的公共字符断了,不连续了
break;
}
printf("最长公共子串为:");
puts(s);
for(i = 0; i < len1+1; i++) //释放动态申请的二维数组
delete[] c[i];
delete[] c;
return max;
}
int main(void)
{
char str1[1000],str2[1000];
printf("请输入第一个字符串:");
gets(str1);
printf("请输入第二个字符串:");
gets(str2);
int len = longest_common_substring(str1, str2);
printf("最长公共连续子串的长度为:%d\n",len);
system("pause");
return 0;
}