LeetCode --- 1143. 最长公共子序列

求两个序列的最长公共子序列长度
[1,3,5,9,10] 和 [1,4,9,10] 的最长公共子序列是 [1,9,10],长度为3
ABCBDAB 和 BDCABA 的最长公共子序列长度为4,可能是BAAB、BDAB、BCAB、BCBA

思路

  • 假设2个序列分别是nums1、nums2
    i ∈ [1,nums1.length]
    j ∈ [1,nums2.length]

  • 假设dp(i, j)是【nums1前i个元素】与【nums2前j个元素】的最长公共子序列长度

  • dp(i, 0)、dp(0, j)初始值均为0

  • 如果nums1[i - 1] = nums2[j - 1],那么dp(i, j) = dp(i - 1, j - 1) + 1

  • 如果nums1[i - 1] != nums2[j - 1],那么dp(i, j) = max { dp(i - 1, j), dp(i, j - 1) }

解法1 - 递归实现

int lcs(int [] nums1, int[] nums2) {
    if (nums1 == null || nums1.length == 0) return 0;
    if (nums2 == null || nums2.length == 0) return 0;
    return lcs(nums1, nums2.length, nums2, num2.length);
}
int lcs(int[] nums1, int i, int[] nums2, int j) {
    if (i == 0 || j == 0) return 0;
    if (nums1[i - 1] != nums2[j - 1]) {
        return Math.max(
        lcs(nums1, i - 1, nums2, j),
        lcs(nums2, i, nums2, j - 1));
    }
    return lcs(nums1, i - 1, nums2, j - 1) + 1;
}
  • 空间复杂度:O(k),k = min { n, m },n、m是2个序列的长度
  • 空间复杂度:O(2^n),当 n = m 时

递归实现分析

在这里插入图片描述

  • 出现了重复递归调用

解法2 - 非递归实现

int lcs(int[] nums1, int[] nums2) {
    if (nums1 == null || nums1.length == 0) return 0;
    if (nums2 == null || nums2.length == 0) return 0;
    int[][] dp = new int[num1.length + 1][nums2.length + 1];
    for (int i = 1; i <= nums1.length; i++) {
        for (int j = 1; j <= nums2.length; j++) {
            if (nums1[i - 1] == nums2[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[nums1.length][nums2.length];
}
  • 空间复杂度:O(n * m)
  • 时间复杂度:O(n * m)
  • dp数组的计算结果如下所示
    在这里插入图片描述

非递归实现 - 优化- 滚动数组

  • 可以使用滚动数组优化空间复杂度
int lcs(int[] nums1, int[] nums2) {
    if (nums1 == null || nums1.length == 0) return 0;
    if (nums2 == null || nums2.length == 0) return 0;
    int[][] dp = new int[2][nums2.length + 1];
    for (int i = 1; i <= nums1.length; i++) {
        int row = i & 1;
        int prevRow = (i - 1) & 1;
        for (int j = 1; j <= nums2.length; j++) {
            if (nums1[i - 1] == nums2[j - 1]) {
                dp[row][j] = dp[prevRow][j - 1] + 1} else {
                dp[row][j] = Math.max(dp[prevRow][j], dp[row][j - 1]);
            }
        }
    }
    return dp[nums1.length & 1][nums2.length];
}

非递归实现 - 优化 - 一维数组

  • 可以将二维数组优化成一维数组,进一步降低空间复杂度
int lcs(int[] nums1, int[] nums2) {
    if (nums1 == null || nums1.length == 0) return 0;
    if (nums2 == null || nums2.length == 0) return 0;
    int[] dp = new int[nums2.length + 1];
    for (int i = 1; i <= nums1.length; i++) {
        int cur = 0;
        for (int j = 1; j <= nums2.length; j++) {
            int leftTop = cur;
            cur = dp[j];
            if (nums1[i - 1] == nums2[j - 1]) {
                dp[j] = leftTop + 1} else {
                dp[j] = Math.max(dp[j], dp[j - 1]);
            }
        }
    }
    return dp[nums2.length];
}
  • 可以将空间复杂度优化至O(k),k = min { n, m }
int lcs(int[] nums1, int[] nums2) {
    if (nums1 == null || nums1.length == 0) return 0;
    if (nums2 == null || nums2.length == 0) return 0;
    int[] rowsNums = nums1, colsNums = nums2;
    if (nums1.length < nums2.length) {
        colsNums = nums1;
        rowsNums = nums2;
    }
    int[] dp = new int[colsNums.length + 1];
    for (int i = 1; i <= rowsNums.length; i++) {
        int cur = 0;
        for (int j = 1; j <= colsNums.length; j++) {
            int leftTop = cur;
            cur = dp[j];
            if (rowsNums[i - 1] == colsNums[j - 1]) {
                dp[j] = leftTop + 1} else {
                dp[j] = Math.max(dp[j], dp[j - 1]);
            }
        }
    }
    return dp[colsNums.length];
}

leetcode 版本

	public int longestCommonSubsequence(String text1, String text2) {
		if (text1 == null || text2 == null) return 0;
		char[] chars1 = text1.toCharArray();  
		if (chars1.length == 0) return 0;
		char[] chars2 = text2.toCharArray();  
		if (chars2.length == 0) return 0;
		char[] rowsChars = chars1, colsChars = chars2;
		if (chars1.length < chars2.length) {
			colsChars = chars1;
			rowsChars = chars2;
		}
		int[] dp = new int[colsChars.length + 1];
		for (int i = 1; i <= rowsChars.length; i++) {
			int cur = 0;
			for (int j = 1; j <= colsChars.length; j++) {
				int leftTop = cur;
				cur = dp[j];
				if (rowsChars[i - 1] == colsChars[j - 1]) {
					dp[j] = leftTop + 1;
				} else {
					dp[j] = Math.max(dp[j], dp[j - 1]);
				}
			}
		}
		return dp[colsChars.length];
    }
发布了188 篇原创文章 · 获赞 19 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/songzhuo1991/article/details/104114846