LeetCode - Medium - 1143

同理dp[0][j]也是0。

其他下标都是随着递推公式逐步覆盖,初始值是默认的即可。

总之,全部都是0,即默认的。

int[][] dp = new int[text1.length() + 1][text2.length() + 1];

4.确定遍历顺序

从递推公式,可以看出,有三个方向可以推出dp[i][j],如图:

在这里插入图片描述

那么为了在递推的过程中,这三个方向都是经过计算的数值,所以要从前向后,从上到下来遍历这个矩阵。

5.举例推导dp数组

以输入:text1 = “abcde”, text2 = “ace” 为例,dp状态如图:

在这里插入图片描述

最后红框dp[text1.length()][text2.length()]为最终结果。

再次重申,dp[i][j]表示 从text1的下标0开始截取长度为i的字符串 与 从text2的下标0开始截取长度为j的字符串 的最长公共子序列的长度。

方法二:方法一的空间优化

进一步地观察,方法一的代码遍历时只需前一行以及目前一行的信息即可。因此,dp数组初始化两行的

注意,用k ^ 1、k ^= 1来切换 dp[0] (第一行) 与 dp[1] (第二行)。

注意,m % 2 与 m & 1 意同。

方法三:方法一的空间优化Plus

再进一步地观察,方法一的代码遍历时只需前一行以及目前一行的前一元素信息即可。因此,dp数组初始化一行的,另加3个变量进行辅助。

最后,优化后的时空杂度分别为:O(m * n),O(min(m, n))。

参考资料

  1. 动态规划:最长公共子序列

  2. [Java/Python 3] Two DP codes of O(mn) & O(min(m, n)) spaces w/ picture and analysis

Submission


public class LongestCommonSubsequence {

// 方法一:标准DP

public int longestCommonSubsequence(String text1, String text2) {

int[][] dp = new int[text1.length() + 1][text2.length() + 1];

for (int i = 1; i <= text1.length(); i++) {

for (int j = 1; j <= text2.length(); j++) {

if (text1.charAt(i - 1) == text2.charAt(j - 1)) {

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[text1.length()][text2.length()];

}

// 方法二:方法一的空间优化

public int longestCommonSubsequence2(String s1, String s2) {

int m = s1.length(), n = s2.length();

if (m < n)// 本判断语句目的可以减少空间复杂度。可以移除本判断语句。

return longestCommonSubsequence2(s2, s1);

int[][] dp = new int[2][n + 1];

for (int i = 1, k = 1; i <= m; ++i, k ^= 1)

for (int j = 1; j <= n; ++j)

if (s1.charAt(i - 1) == s2.charAt(j - 1))

dp[k][j] = 1 + dp[k ^ 1][j - 1];

else

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

return dp[m & 1][n];

}

// 方法三:方法一的空间优化Plus

public int longestCommonSubsequence3(String text1, String text2) {

int m = text1.length(), n = text2.length();

if (m < n) {// 本判断语句目的可以减少空间复杂度。可以移除本判断语句。

return longestCommonSubsequence3(text2, text1);

}

int[] dp = new int[n + 1];

for (int i = 1; i <= text1.length(); ++i) {

for (int j = 1, left = 0, leftUp = 0, newOne = 0; j <= text2.length(); ++j) {

if (text1.charAt(i - 1) == text2.charAt(j - 1)) {

newOne = leftUp + 1;

} else {

newOne = Math.max(left, dp[j]);

}

leftUp = dp[j];

left = dp[j] = newOne;// 为同行下一元素以及下行元素做准备

}

}

return dp[n];

}

}

Test


import static org.junit.Assert.*;

import org.junit.Test;

public class LongestCommonSubsequenceTest {

@Test

public void test() {

LongestCommonSubsequence obj = new LongestCommonSubsequence();

assertEquals(3, obj.longestCommonSubsequence(“abcde”, “ace”));

assertEquals(3, obj.longestCommonSubsequence(“ace”, “abcde”));

assertEquals(3, obj.longestCommonSubsequence(“abc”, “abc”));

assertEquals(0, obj.longestCommonSubsequence(“abc”, “def”));

}

@Test

public void test2() {

LongestCommonSubsequence obj = new LongestCommonSubsequence();

assertEquals(3, obj.longestCommonSubsequence2(“abcde”, “ace”));

assertEquals(3, obj.longestCommonSubsequence2(“ace”, “abcde”));

assertEquals(3, obj.longestCommonSubsequence2(“abc”, “abc”));

assertEquals(0, obj.longestCommonSubsequence2(“abc”, “def”));

}

@Test

public void test3() {

LongestCommonSubsequence obj = new LongestCommonSubsequence();

assertEquals(3, obj.longestCommonSubsequence3(“abcde”, “ace”));

assertEquals(3, obj.longestCommonSubsequence3(“ace”, “abcde”));

assertEquals(3, obj.longestCommonSubsequence3(“abc”, “abc”));

assertEquals(0, obj.longestCommonSubsequence3(“abc”, “def”));

}

@Test

public void testOther() {

面试资料整理汇总

成功从小公司跳槽进蚂蚁定级P7,只因刷了七遍这些面试真题

成功从小公司跳槽进蚂蚁定级P7,只因刷了七遍这些面试真题

这些面试题是我朋友进阿里前狂刷七遍以上的面试资料,由于面试文档很多,内容更多,没有办法一一为大家展示出来,所以只好为大家节选出来了一部分供大家参考。

面试的本质不是考试,而是告诉面试官你会做什么,所以,这些面试资料中提到的技术也是要学会的,不然稍微改动一下你就凉凉了

在这里祝大家能够拿到心仪的offer!
;

}

@Test

public void testOther() {

面试资料整理汇总

[外链图片转存中…(img-Kq76CHkY-1719165073601)]

[外链图片转存中…(img-Zca6AlMZ-1719165073602)]

这些面试题是我朋友进阿里前狂刷七遍以上的面试资料,由于面试文档很多,内容更多,没有办法一一为大家展示出来,所以只好为大家节选出来了一部分供大家参考。

面试的本质不是考试,而是告诉面试官你会做什么,所以,这些面试资料中提到的技术也是要学会的,不然稍微改动一下你就凉凉了

在这里祝大家能够拿到心仪的offer!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值