package com.duoduo.test1;
/**
* 给定两个序列X={ x1,x2,.....xm} Y={y1,y2///yn} 找出两者的一个最长的公共子序列z
* 采用动态规划的思想
* 1 分析最优解的结构特征 假设已经知道了最优解
* 2 建立最优解的递归式
* 3 自底向上求解最优值 并记录最优值和最优策略
* 4 构造最优解
*
* 算法设计: 确定合适的数据结构---》初始化--》循环得到最长长度--》递推来源得到最优解
*/
import java.util.Scanner;
public class Test4_2 {
//已知两个字符串 求解公共最长子序列
static String s1;
static String s2;
public static void main(String [] args) {
Scanner sc=new Scanner(System.in);
System.out.print("输入第一个字符串S1:");
s1= sc.next();
System.out.print("输入第二个字符串S2:");
s2=sc.next();
int len1=s1.length(); //计算两个字符串的长度
int len2=s2.length();
int [][] c=new int[len1+1][len2+1]; //记录最长公共子序列长度
int [][] b=new int[len1+1][len2+1]; //记录最长子序列的来源
/*初始化 第一行第一列均初始化为0*/
for(int i=0;i<=len1;i++)
c[i][0]=0;
for(int j=0;j<=len2;j++)
c[0][j]=0;
LCSL(c,b); //求解最长公共子序列
System.out.println("S1 和S2的最长公共子序列长度为 :"+c[len1][len2]);
System.out.println("S1 和S2的最长公共子序列为 :");
print(b,len1,len2); //递归构造最长公共子序列
}
/*求解最长公共子序列 */
public static void LCSL(int [][] c,int[][] b) {
int i,j;
//循环遍历字符串S1 和S2 比较两者是否相等
for( i=1; i<=s1.length();i++) {
for(j=1;j<=s2.length();j++) {
if(s1.charAt(i-1)==s2.charAt(j-1)) { //字符下标从0开始
//若当前字符相等 则公共子序列长度=该字符前的最长公共子序列+1
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}else {
if(c[i][j-1]>=c[i-1][j]) { //不等 找出两者最大值 相等默认取左值
c[i][j]=c[i][j-1]; //取左值
b[i][j]=2;
}else {
c[i][j]=c[i-1][j]; //取上面值
b[i][j]=3;
}
}
}
}
}
/*递归构造最长公共子序列最优解*/
public static void print(int[][] b,int i,int j) {
if(i==0 || j==0)
return; //若有其中之一为0 则停止 (递归结束条件)
if(b[i][j]==1) { //若来源为1 则递归左上角
print(b,i-1,j-1);
System.out.print(s1.charAt(i-1)); //并打印此值
}else if(b[i][j]==2) {
print(b,i,j-1); //来源左侧
}else {
print(b,i-1,j); //来源上面
}
}
}
结果验证:
算法解析及优化:
时间复杂度:每个数组单元的计算耗费O(1)时间,如果两个字符串的长度分别是m, n,那么算法时间复杂度O(m*n)
空间复杂度:两个二维数组 c[][] ,b[][],占用的空间 O(m*n).
算法优化: 直接用c[i][j] 来判断来源于哪个值,从而不用b[][], 这样可以节省O(m*n)数量级仍然没有变化
本文介绍了如何使用动态规划解决最长公共子序列问题,提供了Java版本的代码实现,并对算法进行了解析和优化。经过优化后的算法时间复杂度为O(m*n),空间复杂度为O(m*n),通过减少辅助数组节省了空间。
3907

被折叠的 条评论
为什么被折叠?



