Double-Sequence DP Problem

Usually inputs are two strings or arrays

Subproblem can be represented as 2-dimentional arrays as f[i][j], usually representing the solutions to subproblem ending at position i of string A and position j of string B (第一个sequence的前i个元素配上第二个sequence的前j个元素)

Use 2-dimentional arrays f[n+1][m+1]

Need to initialize f[i][0] and f[0][j], and remember Java will automatically assign 0(for integers) or false(for boolean) for arrays


Longest Common Subsequence

We have a specific article for this topic, no more details here.


Edit Distance

Analysis:

  • Subproblem: f[i][j]: minimum steps needed to convert A(0,i-1) to B(0,j-1) (string A的前i个字符需要的多少次编辑转换为string B的前j个字符)

  • Initialize: f[i][0]=i, a string with length i needs to delete i times to become an empty string; f[0][j]=j, an empty string needs to insert j times to become a string with length j

  • Function: if A.charAt(i-1)==B.charAt(j-1), f[i][j]=f[i-1][j-2], no need to modification to last character; else, f[i][j]=MIN(f[i-1][j],f[i][j-1],f[i-1][j-1])+1, corresponding to deletion, insertion, replacement separately

  • Answer: f[A.length()][B.length()]

public int minDistance(String word1, String word2) {

        if (word1 == null)
            return word2.length();
        if (word2 == null)
            return word1.length();

        int M = word1.length();
        int N = word2.length();
        int[][] distance = new int[M+1][N+1];

        // Initialization
        distance[0][0] = 0;
        // Need to delete i characters to become an empty string
        for (int i=1; i<=M; i++) {
            distance[i][0] = i;
        }
        // Need to add j characters to become word2 from empty string
        for (int j=1; j<=N; j++) {
            distance[0][j] = j;
        }
        // Function
        for (int i=1; i<=M; i++) {
            for (int j=1; j<=N; j++) {
                distance[i][j] = Math.min(distance[i-1][j-1], 
                                    Math.min(distance[i-1][j], distance[i][j-1]))+1;
                if (word1.charAt(i-1) == word2.charAt(j-1))
                    distance[i][j] = distance[i-1][j-1];
            }
        }
        // Answer
        return distance[M][N];
    }

Distinct Subsequences

题目理解:计算S有多少个跟T相同的distinct subsequences

Analysis:

  • Subproblem: f[i][j]: S的前i个字符里选取T的前j个字符有多少方案

  • Initialize: f[i][0]=1, just one subsequence to match empty string; f[0][j]=0(j>0), empty string has no way offer a subsequence to match non-empty string

  • Function: if S.charAt(i-1)==T.charAt(j-1), f[i][j]=f[i-1][j-1]+f[i-1][j]; else, f[i][j]=f[i-1][j].

    无论S[i-1]的字符与T[j-1]的字符是否相等,dp[i][j] >= dp[i-1][j].就是说,假设T已经匹配了i-1个字符,得到匹配个数为dp[i-1][j].现在无论S[i-1]是不是和T[j-1]匹配,匹配的个数至少是dp[i-1][j]。除此之外,当S[i-1]和T[j-1]相等时,还可以让S[i-1]和T[j-1]去匹配。

  • Answer: f[S.length()][T.length()]

public int numDistinct(String S, String T) {

        if (S == null || T == null)
            return 0;

        int M = S.length();
        int N = T.length();
        int[][] dp = new int[M+1][N+1];

        // Initialize
        // dp[0][0] = 1;
        for (int i=0; i<=M; i++) {
            dp[i][0] = 1;
        }
        for (int j=1; j<=N; j++) {
            dp[0][j] = 0;
        }
        // Function
        for (int i=1; i<=M; i++) {
            for (int j=1; j<=N; j++) {
                if (S.charAt(i-1) == T.charAt(j-1))
                    dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
                else
                    dp[i][j] = dp[i-1][j];
            }
        }
        // Answer
        return dp[M][N];
    }

Interleaving String

Analysis: The inputs are three strings but we don't need to build 3-dimentional arrays, cause i+j=position of the third string.

  • Subproblem: f[i][j]: if we can form string_3 ending at position i+j using first i chars of string_1 and j chars of string_2 (s1的前i个字符加上s2的前j个字符能否组成s3的前i+j个字符)

  • Initialize: f[0][0]=true; f[i][0]=(s1.charAt(i-1) == s3.charAt(i-1) && f[i-1][0] == true); f[0][j]=(s2.charAt(j-1) == s3.charAt(j-1) && dp[0][j-1] == true)

  • Function: **f[i][j]=(s1.charAt(i-1) == s3.charAt(i+j-1) && dp[i-1][j])

              || (s2.charAt(j-1) == s3.charAt(i+j-1) && dp[i][j-1])** (两个string中任意一个可以满足即可)
    
  • Answer: f[s1.length()][s2.length()]

public boolean isInterleave(String s1, String s2, String s3) {

        if (s1.length()+s2.length() != s3.length())
            return false;

        int M = s1.length();
        int N = s2.length();
        boolean[][] dp = new boolean[M+1][N+1];
        // Initialize
        // Other elements will be automatically assigned to false
        dp[0][0] = true;
        for (int i=1; i<=M; i++) {
            if (s1.charAt(i-1) == s3.charAt(i-1) && dp[i-1][0] == true)
                dp[i][0] = true;
        }
        for (int j=1; j<=N; j++) {
            if (s2.charAt(j-1) == s3.charAt(j-1) && dp[0][j-1] == true)
                dp[0][j] = true;
        }
        // Function
        for (int i=1; i<=M; i++) {
            for (int j=1; j<=N; j++) {
                if ((s1.charAt(i-1) == s3.charAt(i+j-1) && dp[i-1][j])
                || (s2.charAt(j-1) == s3.charAt(i+j-1) && dp[i][j-1]))
                    dp[i][j] = true;
            }
        }
        // Answer
        return dp[M][N];
    }

results matching ""

    No results matching ""