最长公共子序列(java和C++)-----动态规划

1、问题

  最长公共子序列问题:给定两个序列X={x1,x2,…,xm},Y={y1,y2,…,yn},找出X和Y的最长公共子序列。

2、算法核心

  设X和Y的最长公共子序列记为LCS(X,Y),
则①:当xm=yn时,只需找LCS(Xm-1,Yn-1),并加上1,因为两序列最后元素相等xm=yn。
 ②:当xm≠yn时,LCS=max{LCS(Xm-1,Yn),LCS(Xm,Yn-1)},不需要加1。
 ③:当至少有一个序列为空时,最大公共子序列长度为0。

3、代码表达式

在这里插入图片描述

4、java代码

import java.util.Scanner;

public class LCSLength {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String X = in.nextLine();//定义字符串X,同时输入字符串X,类似C++的cin
        String Y = in.nextLine();//定义字符串Y,同时输入字符串Y,类似C++的cout
        int[][] c = new int[50][50];//创建一个数组空间
        int Len1 = X.length();//分别取X和Y的长度,当然不取也行,但反复写X.length太麻烦
        int Len2 = Y.length();
        for (int i = 0; i < Len1; i++)//有一个字符串为空,则最大公共子序列长度必为0
            c[0][i] = 0;
        for (int i = 0; i < Len2; i++)//同上一句
            c[i][0] = 0;
        for (int i = 1; i <= Len1; i++) {//算法核心部分。为什么这里是等号呢????看下边注意!
            for (int j = 1; j <= Len2; j++) {
                if (X.charAt(i - 1) == Y.charAt(j - 1))
                    c[i][j] = c[i - 1][j - 1] + 1;//①若X与Y的最后一个字符相同,则i与j都减一,往对角线的左上角找并+1。②就是靠这个+1把数字填上的。
                else
                    c[i][j] = Math.max((c[i - 1][j]), (c[i][j - 1]));//如果末尾两个值不相等,则i-1或j-1,即在回前一行或前一列一个位置找(上面或左边一个位置)。
            }
        }

        for (int i = 0; i <= Len2; i++) {//第一个位置空白,Y从第二个位置开始输出。下面的X同理
            if (i != 0)
                System.out.print(" " + Y.charAt(i - 1));//输出数组Y的值,在第一行。 (1个空格)
            else
                System.out.print("    ");//(4个空格,加上面的1个空格,共5个空格 )
        }
        System.out.println();

        for (int i = 0; i <= Len1; i++) {
            if (i != 0)//故实际的X与Y是从第二个位置开始输出,X从第二列开始全部输出数组X的值。
                System.out.print(" " + X.charAt(i - 1));
            else//else即i=0,即第一列(数组从0开始计数),第一个位置输出空白,因为第一个位置默认为 空序列。
                System.out.print("  ");//2个空格
            for (int j = 0; j <=Len2;j++){
                System.out.print(" "+c[i][j]);//前面1个空格,加else那里的2个空格,则此时空出3个空格,与上面对齐
            }
            System.out.println();
        }
        System.out.println();
        System.out.println("LCSLength="+c[Len1][Len2]);//最长公共子序列在两个数组尽头的交汇处,所以是Len1和Len2
    }
}

  注意:java代码里,前半部分的先是i<Len1,后是i<=Len1,为什么一个没有等号,下一个有等号。是因为没等号的是数组,数组从0开始计数,而有等号的是字符串,字符串从1开始计数!。

5、两个参考例子的结果(java)

在这里插入图片描述
在这里插入图片描述
图解

在这里插入图片描述

6、C++代码

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
        string X,Y;
        int c[50][50];
        int main(){
        cin>>X>>Y; 
        int len1 = X.length(),len2 = Y.length();
        for(int i = 1; i <= len1; i++){
        c[i][0] = 0;//i=0或j=0,则有一个数组为空,那么最大公共子序列必为0 
        c[0][i] = 0;
        }
        for(int i = 1; i <= len1; i++){
        for(int j = 1; j <= len2; j++){
        if(X[i-1] == Y[j-1])
        c[i][j] = c[i-1][j-1]+1;//如果末尾两个值相等,则i与j都减一,往对角线的左上角找/如果末尾两个值不相等,则i-1或j-1,即在回前一行或前一列一个位置找并+1。。就是靠这个+1把数字填上的 
        else
        c[i][j] = max(c[i][j-1],c[i-1][j]);//如果末尾两个值不相等,则i-1或j-1,即在回前一行或前一列一个位置找并+1。 

        }
        }
        
        for(int i = 0; i <= len2; i++){//第一个位置空白,Y从第二个位置开始输出。下面的X同理 
		  if(i!=0)
            cout<<" "<<Y[i-1];//输出数组Y的值,在第一行。 (1个空格) 
          else
            cout<<"    ";//(4个空格,加上面的1个空格,共5个空格 ) 
		}
          cout<<"\n";
        
        for(int i = 0 ; i <= len1; i++){
    	  if(i != 0)//故实际的X与Y是从第二个位置开始输出,X从第二列开始全部输出数组X的值。
            cout<<" "<<X[i-1]; 
          else//else即i=0,即第一列(数组从0开始计数),第一个位置输出空白,因为第一个位置默认为 空序列。
            cout<<"  ";//2个空格 
            
        for(int j = 0; j <= len2; j++){
            cout<<" "<<c[i][j];//前面1个空格,加else那里的2个空格,则此时空出3个空格,与上面对齐 
        }
            cout<<"\n";
        }
            
			cout<<"\n";  
            cout<<"MaxLength = "<<c[Len1][Len2];//最长公共子序列在两个数组尽头的交汇处,所以是Len1和Len2 
        return 0;
        } 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值