博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
每天一道算法题(5)——求2个字符串的最长公共子序列和最长公共子字符串
阅读量:5787 次
发布时间:2019-06-18

本文共 3020 字,大约阅读时间需要 10 分钟。

       题目:如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,则字符串一称之为字符串二的子串。注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中。请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。
       例如:输入两个字符串BDCABA 和ABCBDAB,字符串BCBA 和BDAB 都是是它们的最长公共子串,则

       输出它们的长度4,并打印任意一个子串。

1.思路

         注意最长子序列并不考虑连续性。对于序列str1,str2,设长度为m,n。建立辅助矩阵 c[m][n],定义c[i][j]为子串str1[0-i]与子串str2[0-j]的最长子序列的长度,则c[m][n]的元素满足如下关系:

       即假设求两字符串Xm ={x0, x1,…xm-1}和Yn={y0 ,y1,…,yn-1}的LCS,如果xm-1=yn-1,那么只需求得Xm-1 和Yn-1 的LCS,并在其后添加xm-1(yn-1)即可;如果xm-1≠yn-1,我们分别求得Xm-1 和Y 的LCS 和Yn-1 和X 的LCS,并且这两个LCS 中较长的一个为X 和Y 的LCS。

       首先可以递归的求解。但是考虑到递归过程中的重复计算问题,此处使用辅助矩阵的方法。定义方向矩阵direction[m][n]. 由上叙,求取c[i,j]可能从c[i-1,j-1] 、c[i,j-1]或者c[i-1,j]三个方向计算得到,分别定义方向0,-1,1。

       对direction矩阵反向遍历,当derection[i][j]==1时,str1[i]或str2[j]即为匹配字符之一。

2.代码

       时间复杂度O(m*n),空间复杂度为O(m,n)

#include
#include
#include"string"using namespace std;//使用递归计算出子序列长度并输出子序列bool getSubsequence(int **b,const string s,stack
& sub,int i,int j){ if(!b||(i*j)==0) return false; if(b[i][j]==0){ sub.push(s[j-1]); getSubsequence(b,s,sub,i-1,j-1);//left-up } else if(b[i][j]==1) getSubsequence(b,s,sub,i-1,j);//up else getSubsequence(b,s,sub,i,j-1);//left return true;}bool LCSubsequence(const string str1, const string str2) { int length1,length2; length1 = str1.size(); length2 = str2.size(); if(!length1||!length2) return false; int **c = new int*[length1+1]; int **direction=new int*[length1+1];//记录搜索方向 for(int i = 0; i < length1+1; i++){ c[i] = new int[length2+1]; c[i][0]=0; //第0列初始化为0 direction[i]=new int[length2+1]; } for(int j = 0; j
c[i][j-1])//1 means up { c[i][j]=c[i-1][j]; direction[i][j]=1; } else//-1 measns left { c[i][j]=c[i][j-1]; direction[i][j]=-1; } } } stack
sub; //getSubsequence(direction,str2,sub,length1,length2);//使用递归计算出子序列长度并输出子序列 int i=length1,j=length2; while(i*j!=0){ if(str1[i-1]==str2[j-1]){ sub.push(str1[i-1]); i--; j--; } else if(direction[i-1][j]>direction[i][j-1]) i--; else j--; } cout<<"length of LCS is "<< sub.size()<

3.求最长公共子字符串

     子字符串需要考虑字符连续问题。由于连续,故只有“左上”搜索方向,只需考虑如何计算c[i][j]即可。此时,若str1[i]==str2[j], c[i][j]=c[i-1][j-1]+1否则等于0。只需考虑最大的c[i][j]按斜对角线输出即可:

#include
#include
#include"string"using namespace std;bool LCSubstring(const string str1, const string str2) { int length1,length2; length1 = str1.size(); length2 = str2.size(); if(!length1||!length2) return false; int **c = new int*[length1+1]; for(int i = 0; i < length1+1; i++){ c[i] = new int[length2+1]; c[i][0]=0; //第0列初始化为0 } for(int j = 0; j
length){ length=c[i][j]; maxI=i; } } } cout<<"最长公共子字符串为---"; for(int i=0;length&&i

    

参考

      1.

转载于:https://www.cnblogs.com/engineerLF/p/5393039.html

你可能感兴趣的文章
Node.js 切近实战(七) 之Excel在线(文件&文件组)
查看>>
浅析ERP软件企业资源的关系与发展
查看>>
bilibili弹幕转ass
查看>>
git安装错误
查看>>
nginx开机启动脚本
查看>>
Oracle——distinct的用法
查看>>
苹果电脑如何读写ntfs格式磁盘
查看>>
【转载】VC遍历文件夹下所有文件和文件夹
查看>>
redis 的mq功能演示
查看>>
编码的法则:c++程序员不可不知的101条经验
查看>>
Ubuntu上安装rvm
查看>>
Ubuntu上通过 RVM 安装 多版本 Ruby/Rails
查看>>
Python 监控主机程序,异常后发送邮件(我的第一只Python程序)
查看>>
thinkphp 连接sql server
查看>>
安全狗服云PC端V2.5.1发布 助力服务器安全运维
查看>>
数据库 设计中的英文术语
查看>>
Android Browser学习七 书签历史模块: 书签UI的实现
查看>>
Android如何在测试程序中删除被测应用私有的原始数据
查看>>
php数组去重复数据的小例子
查看>>
【LeetCode】461. Hamming Distance (java实现)
查看>>