题目:如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,则字符串一称之为字符串二的子串。注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中。请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。
例如:输入两个字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它们的最长公共子串,则输出它们的长度4,并打印任意一个子串。
分析:求最长公共子串(Longest Common Subsequence, LCS)是一道非常经典的动态规划题,因此一些重视算法的公司像MicroStrategy都把它当作面试题。
完整介绍动态规划将需要很长的篇幅,因此我不打算在此全面讨论动态规划相关的概念,只集中对LCS直接相关内容作讨论。如果对动态规划不是很熟悉,请参考相关算法书比如算法讨论。
考虑最长公共子序列问题如何分解成子问题,设A=“a0,a1,…,am-1”,B=“b0,b1,…,bn-1”,并Z=“z0,z1,…,zk-1”为它们的最长公共子序列。不难证明有以下性质:
(1) 如果am-1==bn-1,则zk-1=am-1=bn-1,且“z0,z1,…,zk-2”是“a0,a1,…,am-2”和“b0,b1,…,bn-2”的一个最长公共子序列;
(2) 如果am-1!=bn-1,则若zk-1!=am-1时,蕴涵“z0,z1,…,zk-1”是“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一个最长公共子序列;
(3) 如果am-1!=bn-1,则若zk-1!=bn-1时,蕴涵“z0,z1,…,zk-1”是“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一个最长公共子序列。
这样,在找A和B的公共子序列时,如果有am-1==bn-1,则进一步解决一个子问题,找“a0,a1,…,am-2”和“b0,b1,…,bm-2”的一个最长公共子序列;如果am-1!=bn-1,则要解决两个子问题,找出“a0,a1,…,am-2”和“b0,b1,…,bn-1”的一个最长公共子序列和找出“a0,a1,…,am-1”和“b0,b1,…,bn-2”的一个最长公共子序列,再取两者中较长者作为A和B的最长公共子序列。
求解:
引进一个二维数组c[][],用c[i][j]记录X[i]与Y[j] 的LCS 的长度,b[i][j]记录c[i][j]是通过哪一个子问题的值求得的,以决定输出最长公共字串时搜索的方向。
我们是自底向上进行递推计算,那么在计算c[i,j]之前,c[i-1][j-1],c[i-1][j]与c[i][j-1]均已计算出来。此时我们根据X[i] == Y[j]还是X[i] != Y[j],就可以计算出c[i][j]。
问题的递归式写成:
回溯输出最长公共子序列过程:
算法分析:
由于每次调用至少向上或向左(或向上向左同时)移动一步,故最多调用(m + n)次就会遇到i = 0或j = 0的情况,此时开始返回。返回时与递归调用时方向相反,步数相同,故算法时间复杂度为Θ(m + n)。
完整的实现代码如下:
复制代码 代码如下:
/**
找出两个字符串的最长公共子串的长度
** author :liuzhiwei
** data :2011-08-15
**/
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int LCSLength(char* str1, char* str2, int **b)
{
int i,j,length1,length2,len;
length1 = strlen(str1);
length2 = strlen(str2);
//双指针的方法申请动态二维数组
int **c = new int*[length1+1]; //共有length1+1行
for(i = 0; i < length1+1; i++)
c[i] = new int[length2+1]; //共有length2+1列
for(i = 0; i < length1+1; i++)
c[i][0]=0; //第0列都初始化为0
for(j = 0; j < length2+1; j++)
c[0][j]=0; //第0行都初始化为0
for(i = 1; i < length1+1; i++)
{
for(j = 1; j < length2+1; j++)
{
if(str1[i-1]==str2[j-1]) //由于c[][]的0行0列没有使用,c[][]的第i行元素对应str1的第i-1个元素
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]=0; //输出公共子串时的搜索方向
}
else if(c[i-1][j]>c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]=1;
}
else
{
c[i][j]=c[i][j-1];
b[i][j]=-1;
}
}
}
/*
for(i= 0; i < length1+1; i++)
{
for(j = 0; j < length2+1; j++)
printf("%d ",c[i][j]);
printf("\n");
}
*/
len=c[length1][length2];
for(i = 0; i < length1+1; i++) //释放动态申请的二维数组
delete[] c[i];
delete[] c;
return len;
}
void PrintLCS(int **b, char *str1, int i, int j)
{
if(i==0 || j==0)
return ;
if(b[i][j]==0)
{
PrintLCS(b, str1, i-1, j-1); //从后面开始递归,所以要先递归到子串的前面,然后从前往后开始输出子串
printf("%c",str1[i-1]); //c[][]的第i行元素对应str1的第i-1个元素
}
else if(b[i][j]==1)
PrintLCS(b, str1, i-1, j);
else
PrintLCS(b, str1, i, j-1);
}
int main(void)
{
char str1[100],str2[100];
int i,length1,length2,len;
printf("请输入第一个字符串:");
gets(str1);
printf("请输入第二个字符串:");
gets(str2);
length1 = strlen(str1);
length2 = strlen(str2);
//双指针的方法申请动态二维数组
int **b = new int*[length1+1];
for(i= 0; i < length1+1; i++)
b[i] = new int[length2+1];
len=LCSLength(str1,str2,b);
printf("最长公共子串的长度为:%d\n",len);
printf("最长公共子串为:");
PrintLCS(b,str1,length1,length2);
printf("\n");
for(i = 0; i < length1+1; i++) //释放动态申请的二维数组
delete[] b[i];
delete[] b;
system("pause");
return 0;
}
程序的效果图如下:
第二种方法为:
复制代码 代码如下:
/**
找出两个字符串的最长公共子串的长度
** author :liuzhiwei
** data :2011-08-15
**/
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int LCSLength(char* str1, char* str2) //求得两个字符串的最大公共子串长度并输出公共子串
{
int i,j,length1,length2;
length1 = strlen(str1);
length2 = strlen(str2);
//双指针的方法申请动态二维数组
int **c = new int*[length1+1]; //共有length1+1行
for(i = 0; i < length1+1; i++)
c[i] = new int[length2+1]; //共有length2+1列
for(i = 0; i < length1+1; i++)
c[i][0]=0; //第0列都初始化为0
for(j = 0; j < length2+1; j++)
c[0][j]=0; //第0行都初始化为0
for(i = 1; i < length1+1; i++)
{
for(j = 1; j < length2+1; j++)
{
if(str1[i-1]==str2[j-1]) //由于c[][]的0行0列没有使用,c[][]的第i行元素对应str1的第i-1个元素
c[i][j]=c[i-1][j-1]+1;
else if(c[i-1][j]>c[i][j-1])
c[i][j]=c[i-1][j];
else
c[i][j]=c[i][j-1];
}
}
//输出公共子串
char s[100];
int len,k;
len=k=c[length1][length2];
s[k--]='\0';
i=length1,j=length2;
while(i>0 && j>0)
{
if(str1[i-1]==str2[j-1])
{
s[k--]=str1[i-1];
i--;
j--;
}
else if(c[i-1][j]<c[i][j-1])
j--;
else
i--;
}
printf("最长公共子串为:");
puts(s);
for(i = 0; i < length1+1; i++) //释放动态申请的二维数组
delete[] c[i];
delete[] c;
return len;
}
int main(void)
{
char str1[100],str2[100];
int length1,length2,len;
printf("请输入第一个字符串:");
gets(str1);
printf("请输入第二个字符串:");
gets(str2);
length1 = strlen(str1);
length2 = strlen(str2);
len=LCSLength(str1,str2);
printf("最长公共子串的长度为:%d\n",len);
system("pause");
return 0;
}
问题拓展:设A、B、C是三个长为n的字符串,它们取自同一常数大小的字母表。设计一个找出三个串的最长公共子串的O(n^3)的时间算法。
思路:跟上面的求2个字符串的公共子串是一样的思路,只不过这里需要动态申请一个三维的数组,三个字符串的尾字符不同的时候,考虑的情况多一些而已。
复制代码 代码如下:
/**
找出三个字符串的最长公共子串的长度
** author :liuzhiwei
** data :2011-08-15
**/
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int max1(int m,int n)
{
if(m>n)
return m;
else
return n;
}
int max2(int x,int y,int z,int k,int m,int n)
{
int max=-1;
if(x>max)
max=x;
if(y>max)
max=y;
if(z>max)
max=z;
if(k>max)
max=k;
if(m>max)
max=m;
if(n>max)
max=n;
return max;
}
int LCSLength(char* str1, char* str2, char* str3) //求得三个字符串的最大公共子串长度并输出公共子串
{
int i,j,k,length1,length2,length3,len;
length1 = strlen(str1);
length2 = strlen(str2);
length3 = strlen(str3);
//申请动态三维数组
int ***c = new int**[length1+1]; //共有length1+1行
for(i = 0; i < length1+1; i++)
{
c[i] = new int*[length2+1]; //共有length2+1列
for(j = 0; j<length2+1; j++)
c[i][j] = new int[length3+1];
}
for(i = 0; i < length1+1; i++)
{
for(j = 0; j < length2+1; j++)
c[i][j][0]=0;
}
for(i = 0; i < length2+1; i++)
{
for(j = 0; j < length3+1; j++)
c[0][i][j]=0;
}
for(i = 0; i < length1+1; i++)
{
for(j = 0; j < length3+1; j++)
c[i][0][j]=0;
}
for(i = 1; i < length1+1; i++)
{
for(j = 1; j < length2+1; j++)
{
for(k = 1; k < length3+1; k++)
{
if(str1[i-1]==str2[j-1] && str2[j-1]==str3[k-1])
c[i][j][k]=c[i-1][j-1][k-1]+1;
else if(str1[i-1]==str2[j-1] && str1[i-1]!=str3[k-1])
c[i][j][k]=max1(c[i][j][k-1],c[i-1][j-1][k]);
else if(str1[i-1]==str3[k-1] && str1[i-1]!=str2[j-1])
c[i][j][k]=max1(c[i][j-1][k],c[i-1][j][k-1]);
else if(str2[j-1]==str3[k-1] && str1[i-1]!=str2[j-1])
c[i][j][k]=max1(c[i-1][j][k],c[i][j-1][k-1]);
else
{
c[i][j][k]=max2(c[i-1][j][k],c[i][j-1][k],c[i][j][k-1],c[i-1][j-1][k],c[i-1][j][k-1],c[i][j-1][k-1]);
}
}
}
}
len=c[length1][length2][length3];
for(i = 1; i < length1+1; i++) //释放动态申请的三维数组
{
for(j = 1; j < length2+1; j++)
delete[] c[i][j];
delete[] c[i];
}
delete[] c;
return len;
}
int main(void)
{
char str1[100],str2[100],str3[100];
int len;
printf("请输入第一个字符串:");
gets(str1);
printf("请输入第二个字符串:");
gets(str2);
printf("请输入第三个字符串:");
gets(str3);
len=LCSLength(str1,str2,str3);
printf("最长公共子串的长度为:%d\n",len);
system("pause");
return 0;
}
程序的效果图如下:
相关推荐:
用AI修改文章,提升写作效率与质量的新时代
GoogleGTP-智能时代的革命性突破,人工智能的新纪元,ai可以降论文ai率吗
AI撰写率:让创作变得更高效,助力内容产业腾飞,人力ai
ChatGPT遇到问题?如何解决“您的应用遇到问题,无法正常启动”困境?,ai下载增强版
AI写作的崛起-“只能AI写作”背后的巨大潜力,舞狮摄影ai
ChatGPTWindows版本:让AI助手成为你的工作与生活得力助手,Ai相减变形
SEO项目:如何通过精确优化提升企业网站排名与转化率,武汉做网站优化的公司
SEO占位:如何在竞争激烈的市场中占得先机?,梁平区省心全网营销推广
ChatGPTApp怎么调大字体?提升阅读体验,让文字更清晰,推荐ai音频
SEO关键词推广软件官网-助力企业实现高效精准的网络营销,圈圈ai
智能AI生成文章释放创作新可能
SEO在广告领域的深度解析:如何利用SEO提升广告效果,网文写作ai工具
文章生成AI:让写作轻松高效的神奇工具
SEO薪资这些,你也能月入过万!,天水网站建设公司
ChatGPT怎么打不开了?解决办法,轻松恢复畅通无阻!,ai订酒店ai对话
SEO优化流程:助力网站快速提升排名的关键策略,1745ai
丹东抖音seo是什么,抖音seo引流 ,ai工具编写作业指导书
目前AI软件有哪些?智能新时代的必备工具
AI批量文章工具,让写作变得高效与轻松,cs机器人ai
SEO优化大全:让你的网站排名轻松破局,精准引流更高效!,274357524ai
seo类文章是什么,seo技术文章 ,ai3.5-ai聊天
SEO优化基础:让你的网站脱颖而出的秘密武器,模仿猫ai
SEO用户:如何为您的网站带来持续流量和转化,惠州网站推广哪个好
ChatGPT360:全方位提升你的工作与生活效率,ai72787
怎么用AI写文:让创作更轻松,效率翻倍
在线AI文章生成器开启智能创作新时代
AI网页设计生成-智能化创造无限可能,ai机甲风背景音乐
ChatGPT在处理文本时可能无法完全理解上下文的复杂性,肌肉ai
seo逻辑是什么,seo思路 ,语音主播怎么ai写作业
SEO做好,企业网站流量翻倍的关键,seo白帽技术有哪些
SEO定价策略:如何根据企业需求定制最佳价格方案,教育培训抖音营销推广
ChatGPT:智能对话开创新时代,ai做渐变直线
好用的AI智能工具,让生活与工作更高效!
seo要懂些什么,seo主要做什么的 ,小艾艾AI
中外链:打通全球流量的桥梁,提升网站排名与流量的双重保障,行业网站建设思路
ChatGPT连了外网也登不了?如何解决这一问题,重新畅享AI助力!,ai少女大瓜
SEO经营:助力企业腾飞的秘密武器,靖边百度关键词排名
SEO中权重是什么意思?让你迅速网站排名的核心秘密!,长颈鹿智能AI点读机
AI会生成同一篇文章吗?揭开智能创作的神秘面纱
ChatGPT画布打不开?如何解决这一常见问题?,Ai怎么储存为Ai格式在桌面
AI上的文章属于原创吗?人工智能创作内容的归属问题
SEO特点与实施策略:提升网站流量与排名的关键,定西抖音seo价格查询
SEO培训:助力企业实现互联网营销的无限可能,平塘网站优化推广价格
ChatGDP人工智能:未来科技赋能企业与个人的智能变革,如何用AI绘制人体
seo规范是什么,seo行业标准 ,啊龙ai音乐
AI免费文章生成器:轻松创作高质量内容的终极工具
自动写文章的AI,提升效率的创作利器
为什么“未备案域名”会成为互联网行业中的重要问题?,江干区seo优化价格
ChatGPT中文版下载免费版:智能对话新时代,尽在,ai光波
不利于seo是什么,不属于seo对网店推广的作用 ,ai渐变下载