Distinct Subsequences

30% Accepted

Given a string S and a string T, count the number of distinct subsequences of T in S.

A subsequence of a string is a new string
which is formed from the original string by deleting some (can be none) of the characters
without disturbing the relative positions of the remaining characters.
(ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).

Have you met this question in a real interview? Yes
Example
Given S = "rabbbit", T = "rabbit", return 3.

Challenge

  • Do it in O(n2) time and O(n) memory.
  • O(n2) memory is also acceptable if you do not know how to optimize memory.

Tags Expand

  • String
  • Dynamic Programming

O(n2) memory 思路

  • Two Sequence DP
  • 很好的解释
  • 仔细理解题意,题目意思不是很明确
  • 画图找规律,直接看不到规律就自己凑规律,其实都是数学原理
  • 画出矩阵型的图去找规律匹配

题意理解

Since you can choose two b from three and there are total of 3 choices, i.e.,

the first and the second
the first and the third
the second and the third


    r a b b b i t
  1 1 1 1 1 1 1 1
r 0 1 1 1 1 1 1 1
a 0 0 1 1 1 1 1 1
b 0 0 0 1 2 3 3 3
b 0 0 0 0 1 3 3 3
i 0 0 0 0 0 0 3 3
t 0 0 0 0 0 0 0 3
从这个表可以看出,无论T的字符与S的字符是否匹配,dp[i][j] = dp[i][j - 1].
就是说,假设S已经匹配了j - 1个字符,得到匹配个数为dp[i][j - 1].
现在无论S[j]是不是和T[i]匹配,匹配的个数至少是dp[i][j - 1]。
除此之外,当S[j]和T[i]相等时,我们可以让S[j]和T[i]匹配,然后让S[j - 1]和T[i - 1]去匹配。
所以递推关系为:
dp[0][0] = 1; // T和S都是空串.
dp[0][1 ... S.length() - 1] = 1; // T是空串,S只有一种子序列匹配。
dp[1 ... T.length() - 1][0] = 0; // S是空串,T不是空串,S没有子序列匹配。
dp[i][j] = dp[i][j - 1] + (T[i - 1] == S[j - 1] ? dp[i - 1][j - 1] : 0).1 <= i <= T.length(), 1 <= j <= S.length()
public class Solution {
    /**
     * @param S, T: Two string.
     * @return: Count the number of distinct subsequences
     */
    public int numDistinct(String S, String T) {
        // write your code here
        int[][] ret = new int[S.length()+1][T.length()+1];
        for (int i = 0 ; i <= T.length(); i++) {
            ret[0][i] = 0;
        }
        for (int i = 0 ; i <= S.length(); i++) {
            ret[i][0] = 1;
        }
        for (int i = 1; i <= S.length(); i++) {
            for (int j = 1; j <= T.length(); j++) {
                if (i < j) {
                    ret[i][j] = 0;
                    continue;
                }
                if (S.charAt(i - 1) != T.charAt(j - 1)) {
                    ret[i][j] = ret[i - 1][j];
                } else {
                    ret[i][j] = ret[i-1][j-1] + ret[i-1][j];
                }
            }
        }

        return ret[S.length()][T.length()];
    }
}

O(n) memory 优化

public class Solution {
    /*
    bbb bb
    state:
    dp[i][j], first i chars of S and first j chars of T, how many distinct subsequences

    function:
    if(s.charAt(i) == s.charAt(j))
    dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]
    else
    dp[i][j] = dp[i - 1][j]
    initialization:
    dp[i][0] = 0;
    dp[0][j] = 0;

    answer:
    dp[m][n]
    */
    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[2][n + 1];
        // for (int i = 0; i <=m; i++) {
        //     dp[i][0] = 1;
        // }
        dp[0][0] = 1;
        dp[1][0] = 1;

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= Math.min(i, n); j++) {
                char schar = s.charAt(i - 1);
                char tchar = t.charAt(j - 1);
                if (schar == tchar) {
                    dp[i % 2][j] = dp[(i - 1) % 2][j - 1] + dp[(i - 1) % 2][j];
                } else {
                    dp[i % 2][j] = dp[(i - 1) % 2][j];
                }
            }
        }
        return dp[m % 2][n];
    }
}

results matching ""

    No results matching ""