/**
* Given a string S and a string T, count the number of distinct subsequences
* of T in S.
*
* Explain: the number of distinct subsequences of S equal to T
*
* 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).
*
* Here is an example:
* S = "rabbbit", T = "rabbit"
*
* Return 3.
*
* Tags: DP, String
*/
class DistinctSubsequences {
public static void main(String[] args) {
}
/**
* DP, 2d array as table, Time O(mn), Space O(mn)
* We keep a m*n matrix and scanning through string S, while
* m = T.length() + 1 and n = S.length() + 1
* and each cell in matrix dp[i][j] means the number of distinct
* subsequences of T.substr(1...i) in S(1...j)
*
* Initialization, dp[0][0] = 1,
* dp[0][j] = 1, means T is empty, and there is always 1 substring
* and dp[i][0] = 0, means S is empty
*
* dp[i][j] = dp[i][j-1] (from S[1...j - 1] no S[j])
* + (dp[i-1][j-1] (S[j] == T[i] and we are going to use S[j])
* or 0) (S[j] != T[i] so we could not use S[j])
*/
public int numDistinct(String s, String t) {
if (s == null || t == null) return 0;
int m = t.length();
int n = s.length();
if (m > n) return 0;
int[][] dp = new int[m + 1][n + 1];
for (int i = 0; i <= n; i++) dp[0][i] = 1;
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
dp[i][j] = dp[i][j - 1] + (t.charAt(i - 1) == s.charAt(j - 1) ? dp[i - 1][j - 1] : 0);
return dp[m][n];
}
/**
* Space optimized, 1D array, build row by row
*/
public int numDistinctOptimal(String s, String t) {
if (s == null || t == null) return 0;
int m = t.length();
int n = s.length();
if (m > n) return 0;
int[] dp = new int[m + 1];
dp[0] = 1;
for (int i = 1; i <= n; i++)
for (int j = m; j >= 1; j--)
// same: path[i] = path[i] + (T[i-1] == S[j-1] ? path[i-1] : 0);
if (t.charAt(j - 1) == s.charAt(i - 1)) dp[j] += dp[j - 1];
return dp[m];
}
}