算法题解:求两个字符串的最长公共子序列问题(JAVA代码详解)

求两个字符串的最长公共子序列问题(JAVA代码详解)

最长公共子序列问题: 给定两个字符串A、B,求A与B的最长公共子序列(子序列不要求是连续的)
举例:
字符串A: abcicba
字符串B:abdkscab
其中:ab、abc、abca都是公共子序列,但是abca是最长公共子序列

从文件读取输入:
1A2C3D4B56
B1D23CA45B6A

输出:
123456
或者 12C4B6都正确

package com.bean.algorithmexec;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class LCS {

	/*
	 * 最长公共子序列问题 给定两个字符串A、B,求A与B的最长公共子序列(子序列不要求是连续的) 
	 * 举例: 
	 * 字符串A: abcicba 
	 * 字符串B:abdkscab
	 * 其中:ab、abc、abca都是公共子序列,但是abca是最长公共子序列
	 * 
	 * 从文件读取输入:
	 * 1A2C3D4B56
	 * B1D23CA45B6A
	 * 
	 * 输出:
	 * 123456 
	 * 
	 * 或者 12C4B6都正确
	 * 
	 * (这里的算法其实存在一个缺陷)
	 */

	public static void main(String[] args) throws FileNotFoundException {
		// TODO Auto-generated method stub

		System.setIn(new FileInputStream("G:\\lcs.txt"));
		Scanner sc = new Scanner(System.in);
       
		String aStr = sc.nextLine(); //读取A字符串
		String bStr = sc.nextLine(); //读取B字符串
		int aLen = aStr.length();
		int bLen = bStr.length();
		//构造DP矩阵
		int[][] dp = new int[aLen + 1][bLen + 1];
		for (int i = 1; i < aLen + 1; i++)
			for (int j = 1; j < bLen + 1; j++)
				if (dp[i - 1][j] == dp[i][j - 1] && aStr.charAt(i - 1) == bStr.charAt(j - 1)
						&& dp[i - 1][j] == dp[i - 1][j - 1])
					dp[i][j] = dp[i - 1][j] + 1;
				else
					dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
		int max = dp[aLen][bLen];
		StringBuilder sb = new StringBuilder();
		while (max > 0) {
			if (dp[aLen - 1][bLen] == dp[aLen][bLen - 1] && dp[aLen - 1][bLen] + 1 == dp[aLen][bLen]) {
				sb.append(aStr.charAt(aLen - 1));
				max--;
				aLen--;
				bLen--;
			} else {
				if (dp[aLen][bLen - 1] == dp[aLen][bLen])
					bLen--;
				else
					aLen--;
			}
		}

		System.out.println(sb.reverse().toString());
	}

}

另一种算法设计

这个问题是一个经典的动态规划问题,先来介绍求解动态规划表的过程。

第1步:

如果str1的长度为M,str2的长度为N,则生成大小为M*N的矩阵dp,行数为M行,列数为N列。
d p [ i ] [ j ] dp[i][j] dp[i][j]的含义是 s t r 1 [ 0... i ] str1[0...i] str1[0...i] s t r 2 [ 0... j ] str2[0...j] str2[0...j]的最长公共子序列的长度。从左向右,从上向下计算矩阵dp。

其中:记str1中从第0个字符到第i个字符为 s t r 1 [ 0... i ] str1[0...i] str1[0...i];记str2中从第0个字符到第j个字符为 s t r 2 [ 0... j ] str2[0...j] str2[0...j]

矩阵dp第一列即 d p [ 0... M − 1 ] [ 0 ] dp[0...M-1][0] dp[0...M1][0] d p [ i ] [ 0 ] dp[i][0] dp[i][0]的含义是 s t r 1 [ 0... i ] str1[0...i] str1[0...i] s t r 2 [ 0 ] str2[0] str2[0]的最长公共子序列长度。
s t r 2 [ 0 ] str2[0] str2[0]只有一个字符,所以 d p [ i ] [ 0 ] dp[i][0] dp[i][0]最大为1。如果 s t r 1 [ i ] = = s t r 2 [ 0 ] str1[i]==str2[0] str1[i]==str2[0],令 d p [ i ] [ 0 ] = 1 dp[i][0]=1 dp[i][0]=1,一旦 d p [ i ] [ 0 ] dp[i][0] dp[i][0]被置为1,之后的 d p [ i + 1... M − 1 ] [ 0 ] dp[i+1...M-1][0] dp[i+1...M1][0]也都为1。

例如: s t r 1 [ 0... M

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值