矩阵最长上升子序列java_算法思想之动态规划(四)——最长公共子序列问题

前言

今天我们继续讨论经典的动态规划问题之最长公共子序列问题。

最长公共子序列问题

问题描述

给定两个字符串str1和str2,返回两个字符串的最长公共子序列的长度。例如,str1="1A2C3”,str2="B1D23”,”123"是最长公共子序列,那么两字符串的最长公共子序列的长度为3。

问题分析

假设两字符串str1和str2的长度分别为n和m。对于这类问题,我们一般可以构建一个

math?formula=n%20%5Ctimes%20m大小的矩阵dp,其中

math?formula=dp%5Bi%5D%5Bj%5D代表的是str1中前

math?formula=i个字符串与str2中前

math?formula=j个字符串的最长公共子序列的长度。

首先,我们需要初始化第0行和第0列的

math?formula=dp%5Bi%5D%5Bj%5D的值,可以通过比较两字符是否相等即可,相等置1,不相等置0,要注意的是一旦在某一位置两字符相等,则该位置后直接置1,代表该位置后的字符串最长的公共子序列为1。对于问题描述中的例子来说,str1中的第1个字符"1"与str2中第1个字符“B”不等,代表"1"与"B"的公共子序列长度为0,即

math?formula=dp%5B0%5D%5B0%5D%20%3D%200;而str1的第1个字符"1"与与str2中第2个字符"1"相等,代表"1"与"B1"的最长公共子序列为1,即

math?formula=dp%5B0%5D%5B1%5D%20%3D%201;显然,"1"与"B1"、"B1D"、"B1D2"、"B1D23"的最长公共子序列均为1,即

math?formula=dp%5B0%5D%5B1%5D%20%3D%20dp%5B0%5D%5B2%5D%20%3D%20dp%5B0%5D%5B3%5D%20%3D%20dp%5B0%5D%5B4%5D%20%3D%201

接下来,我们就需要从左到右,由上至下依次计算

math?formula=dp%5Bi%5D%5Bj%5D。对于

math?formula=i%20%5Cgeq%201%2C%20j%20%5Cgeq%201

math?formula=dp%5Bi%5D%5Bj%5D%20%3D%20%3F。我们可以列举出

math?formula=dp%5Bi%5D%5Bj%5D所有可能的取值:

(1) 如果

math?formula=str1%5Bi%5D%20%3D%3D%20str2%5Bj%5D,那么最长公共子序列的长度为前

math?formula=i-1个子字符串与前

math?formula=j-1个子字符串的最长公共子序列长度

math?formula=%2B1,即

math?formula=dp%5Bi%5D%5Bj%5D%20%3D%20dp%5Bi-1%5D%5Bj-1%5D%2B1

(2) 如果

math?formula=str1%5Bi%5D%20%5Cneq%20str2%5Bj%5D,那么最长公共子序列的长度有可能为:

math?formula=i-1个子字符串与前

math?formula=j个子字符串的最长公共子序列长度,即

math?formula=dp%5Bi-1%5D%5Bj%5D

math?formula=i个子字符串与前

math?formula=j-1个子字符串的最长公共子序列长度,即

math?formula=dp%5Bi%5D%5Bj-1%5D

在二者之间取较大的那一个即可,即

math?formula=dp%5Bi%5D%5Bj%5D%20%3D%20max%20%5C%7B%20dp%5Bi-1%5D%5Bj%5D%2C%20dp%5Bi%5D%5Bj-1%5D%20%5C%7D

代码实现

通过问题分析,可以很容易得用代码实现,下面给出算法的java实现。

public class LCS {

public int findLCS(String A, int n, String B, int m) {

return core(A, n, B, m);

}

public int core(String A, int n, String B, int m) {

if (n == 0 || m == 0) {

return 0;

}

int[][] dp = new int[n][m];

// 初始化第0行

for (int i = 0; i < m; i++) {

if (A.charAt(0) == B.charAt(i)) {

for (int j = i; j < m; j++) {

dp[0][j] = 1;

}

break;

} else {

dp[0][i] = 0;

}

}

// 初始化第0列

for (int i = 0; i < n; i++) {

if (A.charAt(i) == B.charAt(0)) {

for (int j = i; j < n; j++) {

dp[j][0] = 1;

}

break;

} else {

dp[i][0] = 0;

}

}

for (int i = 1; i < n; i++) {

for (int j = 1; j < m; j++) {

if (A.charAt(i) == B.charAt(j)) {

dp[i][j] = dp[i - 1][j - 1] + 1;

} else {

dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);

}

}

}

return dp[n - 1][m - 1];

}

public static void main(String[] args) {

LCS lcs = new LCS();

String A = "1A2C3";

int n = A.length();

String B = "B1D23";

int m = B.length();

int res = lcs.findLCS(A, n, B, m);

System.out.println(res);

}

}

其他经典问题

未来几篇博文,我将继续对经典的动态规划问题进行整理,敬请关注~

由于本人水平有限,文章难免有欠妥之处,欢迎大家多多批评指正!

写在最后

欢迎大家关注我的个人博客复旦猿。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值