两个字符串的所有公共最长子序列
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了两个字符串的所有公共最长子序列相关的知识,希望对你有一定的参考价值。
子序列可以是不连续的,严格递增的情况下是子序列就行。
比如A,B,C,B,D,A,B和B,D,C,A,B,A的最长公共子序列是B,D,A,B
、B,C,B,A、B,C,A,B等
date: 09-11-26
BY: zggxjxcgx
算法: 判断较短串是否为较长串的子序列,如果是则得到结果;
否则,对较短串进行逐个字符删除操作(将字符替换为'#'表示删除)。
删除操作用递归函数进行实现。每层递归删除一个字符,
若删除一个字符后未得到匹配子序列,则还原该字符所在位置。
第n层递归未找到匹配子序列,则将递归层数加1,重复删除直到剩下空串。
*/
#include<stdio.h>
#include<string.h>
int dep=0; /* 较短串的长度 */
int depflag=0; /*下一步要探测的深度 */
int lastflag=0; /* 是否找到匹配子序列,1为找到 */
int count=0; /* 目标结果的个数 */
int mystrcmp(char *s1,char *s2) /* 判断s2是否为 s1的子串 */
while(*s1 && *s2)
if(*s2=='#') s2++;
else if(*s2 == *s1) s1++; s2++;
else s1++;
while(*s2=='#') s2++;
if(*s2=='\0') return 1;
return 0;
void pristr(char *str) /* 打印最长子序列 */
if(0==count++) printf("\n公共最长子序列:\n");
printf("%2d:",count);
while(*str)
if(*str!='#')
printf("%c",*str);
str++;
printf("\n");
/*递归函数求最长子序列。start 控制下一个要检测的字符,deptemp控制递归的深度,first为's'表示第一层递归 */
int fun(char *str1,char *str2,char *start,int deptemp,char first)
int i=0,j=0;
char *s,cback;
do
s=start;
if('s'==first) deptemp=depflag; /* 在第一层设置递归深度 */
while(*s)
if(*s=='#') s++; continue;
cback=*s; *s='#'; /* 删除当前字符*/
if(mystrcmp(str1,str2)) pristr(str2); lastflag=1; /*找到匹配,将lastflag设为1,在完成深度为deptemp+1的探测(找到所有匹配)后退出递归 */
else if(deptemp>0) fun(str1,str2,s+1,deptemp-1,'n'); /* 深度探测,s+1表示从下一个位置开始删除 */
*s=cback; s++; /* 还原该位置的字符,以便下次进行探测 */
if('s'==first) ++depflag; /* 删除depflag+1个字符还未找到,则递归深度加1 */
while(depflag<dep-1 && 's'==first && 0==lastflag); /* 第一层递归具有特殊意义,由三个变量标记是否第一层 */
if(lastflag) return 1; /* lastflag 为1 表示找到匹配子序列 */
return 0;
void main()
char *s1,*s2;
char st1[]="asfdebjewcwedwk";
char st2[]="sabscdkwss"; // kwfsa
if(strlen(st1)>strlen(st2)) s1=st1,s2=st2; /* 将s1设为较长的串 */
else s1=st2,s2=st1;
printf("\nstr1:%s\nstr2:%s\n",s1,s2);
dep=strlen(s2); /* 得到较短串的长度 */
if(mystrcmp(s1,s2)) pristr(s2);
else if(0==fun(s1,s2,s2,0,'s')) printf("\n没有公共元素!\n");
// printf("%d\n",mystrcmp("afdebjewcwedw","abcdw#"));
参考技术A /* 目标:输出两个字符串的所有公共最长子序列
date: 09-11-26
BY: zggxjxcgx
算法: 判断较短串是否为较长串的子序列,如果是则得到结果;
否则,对较短串进行逐个字符删除操作(将字符替换为'#'表示删除)。
删除操作用递归函数进行实现。每层递归删除一个字符,
若删除一个字符后未得到匹配子序列,则还原该字符所在位置。
第n层递归未找到匹配子序列,则将递归层数加1,重复删除直到剩下空串。
*/
#include<stdio.h>
#include<string.h>
int dep=0; /* 较短串的长度 */
int depflag=0; /*下一步要探测的深度 */
int lastflag=0; /* 是否找到匹配子序列,1为找到 */
int count=0; /* 目标结果的个数 */
int mystrcmp(char *s1,char *s2) /* 判断s2是否为 s1的子串 */
while(*s1 && *s2)
if(*s2=='#') s2++;
else if(*s2 == *s1) s1++; s2++;
else s1++;
while(*s2=='#') s2++;
if(*s2=='\0') return 1;
return 0;
void pristr(char *str) /* 打印最长子序列 */
if(0==count++) printf("\n公共最长子序列:\n");
printf("%2d:",count);
while(*str)
if(*str!='#')
printf("%c",*str);
str++;
printf("\n");
/*递归函数求最长子序列。start 控制下一个要检测的字符,deptemp控制递归的深度,first为's'表示第一层递归 */
int fun(char *str1,char *str2,char *start,int deptemp,char first)
int i=0,j=0;
char *s,cback;
do
s=start;
if('s'==first) deptemp=depflag; /* 在第一层设置递归深度 */
while(*s)
if(*s=='#') s++; continue;
cback=*s; *s='#'; /* 删除当前字符*/
if(mystrcmp(str1,str2)) pristr(str2); lastflag=1; /*找到匹配,将lastflag设为1,在完成深度为deptemp+1的探测(找到所有匹配)后退出递归 */
else if(deptemp>0) fun(str1,str2,s+1,deptemp-1,'n'); /* 深度探测,s+1表示从下一个位置开始删除 */
*s=cback; s++; /* 还原该位置的字符,以便下次进行探测 */
if('s'==first) ++depflag; /* 删除depflag+1个字符还未找到,则递归深度加1 */
while(depflag<dep-1 && 's'==first && 0==lastflag); /* 第一层递归具有特殊意义,由三个变量标记是否第一层 */
if(lastflag) return 1; /* lastflag 为1 表示找到匹配子序列 */
return 0;
void main()
char *s1,*s2;
char st1[]="asfdebjewcwedwk";
char st2[]="sabscdkwss"; // kwfsa
if(strlen(st1)>strlen(st2)) s1=st1,s2=st2; /* 将s1设为较长的串 */
else s1=st2,s2=st1;
printf("\nstr1:%s\nstr2:%s\n",s1,s2);
dep=strlen(s2); /* 得到较短串的长度 */
if(mystrcmp(s1,s2)) pristr(s2);
else if(0==fun(s1,s2,s2,0,'s')) printf("\n没有公共元素!\n");
// printf("%d\n",mystrcmp("afdebjewcwedw","abcdw#"));
动态规划之最长公共子序列(LCS)
转自:http://segmentfault.com/blog/exploring/
LCS
问题描述
定义: 一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。 例如:输入两个字符串 BDCABA 和 ABCBDAB,字符串 BCBA 和 BDAB 都是是它们的最长公共子序列,则输出它们的长度 4,并打印任意一个子序列. (Note: 不要求连续)
判断字符串相似度的方法之一 - LCS 最长公共子序列越长,越相似。
July 10分钟讲LCS视频:http://www.julyedu.com/video/play/id/9
复杂度
对于一般性的 LCS 问题(即任意数量的序列)是属于 NP-hard。但当序列的数量确定时,问题可以使用动态规划(Dynamic Programming)在多项式时间解决。可达时间复杂度:O(m*n)
暴力方法
动态规划方法
最优子结构性质: 设序列 X=<x1, x2, …, xm>
和 Y=<y1, y2, …, yn>
的一个最长公共子序列 Z=<z1, z2, …, zk>
,则:
- 若
xm = yn
,则zk = xm = yn
则Zk-1
是Xm-1
和Yn-1
的最长公共子序列;
2. 若 xm ≠ yn
, 要么Z
是 Xm-1
和 Y
的最长公共子序列,要么 Z
是X
和 Yn-1
的最长公共子序列。 2.1 若 xm ≠ yn
且 zk≠xm
,则 Z
是 Xm-1
和 Y
的最长公共子序列; 2.2 若 xm ≠ yn 且 zk ≠yn
,则 Z
是X
和 Yn-1
的最长公共子序列。 综合一下2 就是求二者的大者
递归结构:
递归结构容易看到最长公共子序列问题具有子问题重叠性质。例如,在计算 X
和 Y
的最长公共子序列时,可能要计算出 X
和 Yn-1
及 Xm-1
和 Y
的最长公共子序列。而这两个子问题都包含一个公共子问题,即计算 Xm-1
和 Yn-1
的最长公共子序列。
递归结构容易看到最长公共子序列问题具有子问题重叠性质。例如,在计算 X
和 Y
的最长公共子序列时,可能要计算出 X
和 Yn-1
及 Xm-1
和 Y
的最长公共子序列。而这两个子问题都包含一个公共子问题,即计算Xm-1
和 Yn-1
的最长公共子序列。
计算最优值: 子问题空间中,总共只有O(m*n)
个不同的子问题,因此,用动态规划算法自底向上地计算最优值能提高算法的效率。
长度表C 和 方向变量B:
以上是关于两个字符串的所有公共最长子序列的主要内容,如果未能解决你的问题,请参考以下文章
如何求两个字符串的最长公共子序列: 如:求串<1,0,0,1,0,1,0,1>和<0,1,0,1,1,0,1,1>的最长公共子序列