115. Distinct Subsequences

Problem

Given two strings s and t, return the number of distinct subsequences of s which equals t.

The test cases are generated so that the answer fits on a 32-bit signed integer.

 

Example 1:

Input: s = "rabbbit", t = "rabbit"
Output: 3
Explanation:
As shown below, there are 3 ways you can generate "rabbit" from s.
rabb[b]it
ra[b]bbit
rab[b]bit
Example 2:

Input: s = "babgbag", t = "bag"
Output: 5
Explanation:
As shown below, there are 5 ways you can generate "bag" from s.
ba[b]g[bag]
ba[bgba]g
b[abgb]ag
[ba]b[gb]ag
[babg]bag

* Note: character in square bracket is removed to make s = t

Approach

Xét ví dụ:
s = rabbbit
t = rabbit
Đề bài bảo tìm số “subsequence” của s sao cho giống với t
Gọi (i, j) lần lượt là index của st
Gọi f(i,j) là số subsequence của chuỗi s[i..n] giống với chuỗi t[j..m] với n, m là chiều dài của s và t

Implementation

1. Recursion + memorization

class Solution {

    private String s;
    private String t;
    private Map<String, Integer> memo;

    public int numDistinct(String s, String t) {
        this.s = s; this.t = t;
        this.memo = new HashMap<>();

        return dfs(0, 0);
    }

    private int dfs(int i, int j) {
        String key = i + "_" + j;
        if (memo.containsKey(key)) return memo.get(key);

        // base case
        // s = "" and t = "abc" => no ways to make s = t
        if (i == s.length() && j < t.length()) {
            return 0;
        }
        
        // remaining case whenever t = "" => 1 way
        if (j == t.length()) {
            return 1;
        }

        // logic
        int ans = 0;
        if (s.charAt(i) == t.charAt(j)) {
            ans += dfs(i+1, j+1) + dfs(i+1, j);
        } else {
            ans += dfs(i+1, j);
        }

        memo.put(key, ans);
        return ans;
    }
}

2. DP

class Solution {
    // convert DFS => dp using 2D matrix
    public int numDistinct(String s, String t) {
        int n = s.length(); int m = t.length();
        int[][] dp = new int[n+1][m+1];

        // t = "" and s is not empty => 1 way to make s = t
        for (int i = 0; i < n; i++) {
            dp[i][m] = 1;
        }
        // s = "" and t is not empty => 0 way to make s = t;
        for (int j = 0; j < m; j++) {
            dp[n][j] = 0;
        }
        // s = "" and t = "" => 1 way to make s = t;
        dp[n][m] = 1;

        for (int i=n-1; i>=0; i--) {
            for (int j=m-1; j>=0; j--) {
                if (s.charAt(i) == t.charAt(j)) {
                    dp[i][j] += dp[i+1][j+1] + dp[i+1][j];
                } else {
                    dp[i][j] += dp[i+1][j];
                }
            }
        }

        return dp[0][0];
    }
}