最长公共子序列(JAVA)

最长公共子序列问题:若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。

给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。

总结起来就是:1.最长公共子序列中的元素是要俩个序列共有的。

                         2.这些元素在原序列的下标必须的递增的。

用动态规划的思路去求解会节约许多时间,可以先求出最长公共子序列的长度,再去求出对应的值。

void LCSLength (char x[] ,char y[], int m, int n, int c[][], int b[][])
	{
	       int i,j;
	       for (i = 1; i <= m; i++) c[i][0] = 0;//第0列设为0
	       for (i = 1; i <= n; i++) c[0][i] = 0;//第0行设为0
	       for (i = 1; i <= m; i++)
	          for (j = 1; j<= n; j++)
	          {
	            if (x[i]==y[j])
	            {
	                 c[i][j]=c[i-1][j-1]+1;
	                 b[i][j]=1;
	            }
	            else if (c[i-1][j]>=c[i][j-1])
	            {
	                 c[i][j]=c[i-1][j];
	                 b[i][j]=2;
	            }
	            else
	            {    c[i][j]=c[i][j-1];
	                 b[i][j]=3;
	            }
	         }
	}

     这个方法是寻找子序列的最大长度。3个判断条件的结果,简单归纳为
     [i-1,j-1] 【i-1,j】
     【i,j-1】    (i,j)
     假如,Xi=Yj,则是左上角b[i][j]=[i-1,j-1]+1。
     如果,俩者不等,假如【i-1,j】大于【i,j-1】,则是取【上】一个值b[i][j]=【i-1,j】。
     假如【i-1,j】小于【i,j-1】,则是取【左】边一个值b[i][j]=【i,j-1】。
     即使俩个【】谁大,b[i][j]就等于谁的值。
     当俩个序列中有第一个值相等时,就将该坐标记为1,并将这个“1”在该行传递下去,直到结束该行。
     在下一行中也将把上一行的“1”继承,如果在此行中有第二个值相同时,就执行b[i][j]=[i-1,j-1]+1,
    就是将本来的“1”+1,变成了2,此时的最大长度就变成了2,以此类推,直至俩个序列都找完,最后的c[i][j]就是所需要的长度。

void LCS(int i,int j, char x[] ,int b[][])
	{
	      if (i ==0 || j==0) return;
	      if (b[i][j]== 1)        //输出该序号
	      {
	           LCS(i-1,j-1,x,b);//【1】
	           System.out.print(x[i]+" ");
	      }
	      else if (b[i][j]== 2)    //向上找
	           LCS(i-1,j,x,b);
	      else                     //b[i][j]=3,向左找
	    	  LCS(i,j-1,x,b);
	}

 该方法是输出子序列,是从大到小寻找。但不会倒序输出,因为当满足第一个if条件时,此时已经找到最后一个元素,
     但首先会执行【1】,即已经去寻找前一个元素,以此类推,直到找到子序列的第一个元素,接着从头到尾输出,完成子序列。

源代码:

import java.util.*;
public class S3_1 {
	
	static char x[]=new char[100];
	static char y[]=new char[100];
	static int c[][]=new int[100][100];
	static int b[][]=new int[100][100];
	int t=0;
	public static void main(String[] args) {
		S3_1 s=new S3_1();
		Scanner sc=new Scanner(System.in);
		System.out.println("输入俩个序列");
		System.out.println("输入序列1、2的长度:");
		int m=sc.nextInt();
		int n=sc.nextInt();
		System.out.println("1:");
		for(int i=1;i<=m;i++) {
			x[i]=sc.next().charAt(0);
		}
		System.out.println("2:");
		for(int i=1;i<=n;i++) {
			y[i]=sc.next().charAt(0);
		}
		s.LCSLength(x, y, m, n, c, b);
		System.out.println("最长公共子序列为:");
		s.LCS(m, n, x, b);	
	}
	void LCSLength (char x[] ,char y[], int m, int n, int c[][], int b[][])
	{
	       int i,j;
	       for (i = 1; i <= m; i++) c[i][0] = 0;//第0列设为0
	       for (i = 1; i <= n; i++) c[0][i] = 0;//第0行设为0
	       for (i = 1; i <= m; i++)
	          for (j = 1; j<= n; j++)
	          {
	            if (x[i]==y[j])
	            {
	                 c[i][j]=c[i-1][j-1]+1;
	                 b[i][j]=1;
	            }
	            else if (c[i-1][j]>=c[i][j-1])
	            {
	                 c[i][j]=c[i-1][j];
	                 b[i][j]=2;
	            }
	            else
	            {    c[i][j]=c[i][j-1];
	                 b[i][j]=3;
	            }
	         }
	}

	void LCS(int i,int j, char x[] ,int b[][])
	{
	      if (i ==0 || j==0) return;
	      if (b[i][j]== 1)        //输出该序号
	      {
	           LCS(i-1,j-1,x,b);//【1】
	           System.out.print(x[i]+" ");
	      }
	      else if (b[i][j]== 2)    //向上找
	           LCS(i-1,j,x,b);
	      else                     //b[i][j]=3,向左找
	    	  LCS(i,j-1,x,b);
	}
	
}
  • 5
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值