本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接
一、题目描述
二、解题思路
1.动态规划
最长公共子序列是十分经典的二维动态规划题目。
说到动态规划,就需要初始化边界+找到状态转移方程。
状态转移方程
定义二维dp数组,其中dp[i][j]代表text1[0:i] 和text2[0:j] 的最长公共子序列的长度。
考虑非边界情况i>0,j>0这时dp[i+1][j+1]该怎么计算?
- 1.text1[i+1]==text2[j+1]时,最长公共子序列的长度是不是得加1。
dp[i][j] = dp[i-1][j-1]+1
- 2.text1[i+1]!=text2[j+1]时,最长公共子序列得长度并没有增加。它的值应从已有数据推导。
已有dp[i-1][j] text1[0:i-1] 和text2[0:j] 的最长公共子序列的长度
dp[i][j-1] text1[0:i] 和text2[0:j-1] 的最长公共子序列的长度
应该取其中的最大值:
max(dp[i−1][j],dp[i][j−1])
因此得到状态转移方程:
边界初始化
dp[i][0],dp[0][j] 如果0代表字符串的第一个字符串,那需要循环去判断设值。
我们可以定义0为空字符串就可以把初始赋值省去,因为空字符的最长公共子序列为0。
因此可以得到:
时间复杂度分析
假设m和n分别是字符串text1和 text2的长度。二维数组dp有m+1行和n+1列,需要对dp中的每个元素进行计算。但因为边界不需要计算因此时间复杂度为:
- O(nm)
空间复杂度分析
假设m和n分别是字符串text1和 text2的长度。因为需要创建一个(m+1)*(n+1)的数组因此空间复杂度为:
- O((n+1)(m+1))
三、代码实现
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length(), n = text2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++) {
char c1 = text1.charAt(i - 1);
for (int j = 1; j <= n; j++) {
char c2 = text2.charAt(j - 1);
if (c1 == c2) {
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[m][n];
}
}
不晓得我讲清楚了没有,请大家多多指教。
今日打卡结束!