差分算法:Myers vs DP

Posted by TimerIzaya on November 10, 2023

最短编辑距离问题 ≈ 最长公共子序列(longestCommonSubsequence, LCS)问题

LCS

  • DP

    假设现要求序列X与Y的LCS,X长度为m,Y长度为n。

    • 假设X[0: m - 1] 与 Y的LCS为R1,是否有可能是答案?当然可能,因为X[m - 1]可能完全没有卵用。
    • 假设X[m] 与 Y[0: n - 1]的LCS的为R2,是否有可能是答案?也可能,因为Y[m - 1]也可能完全没有卵用。
    • 假设X[0: m - 1]与Y[0: n - 1]的LCS为R3,是否有可能是答案?
      • 如果X[m - 1]和Y[m - 1]不同,那都没有卵用,那么R3可能是答案。
      • 如果X[m - 1]和Y[m - 1]相同,那有点用了,R3+1可能是答案。

    当前的最优解,取决于相邻三处的最优解。

    所以动态方程为

    令dp[i][j]为X[0: i]与Y[0: j]的最优解
    则dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1] + dp[i] == dp[j] ? 1 : 0)
    

    时间复杂度为o(m * n), 空间复杂度O(m * n)

    优化1:滚动数组

    还是太慢了,空间需要O(m * 2)

    优化2:滚动对角线

    当前场景的极致优化,空间只需要O(m)

    class Solution {
        public int longestCommonSubsequence(String text1, String text2) {
            char[] arr1 = text1.toCharArray(), arr2 = text2.toCharArray();
            int m = arr1.length, n = arr2.length;
            int[] dp = new int[m + 1];
            int ret = 0;
            for (int i = 1; i < n + 1; i++) {
                char c = arr2[i - 1];
                int dia = 0;
                for (int j = 1; j < m + 1; j++) {
                    int left = dp[j - 1], upper = dp[j];
                    int same = c == arr1[j - 1] ? 1 : 0;
                    dp[j] = Math.max(dia + same, Math.max(left, upper));
                    dia = upper;
                    ret = Math.max(ret, dp[j]);
                }
            }
            return ret;
        }
    }
    
  • Myers(BFS+Greedy)