Problem Statement:
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.
Solution:
1. Recursion and Memoization:
class Solution {
public int numDistinct(String s, String t) {
if(s.length() < t.length()){
return 0;
}
int[][] dp = new int[s.length()][t.length()];
for(int[] row: dp){
Arrays.fill(row, -1);
}
return numDistinctUtil(s, t, 0, 0, dp);
}
public int numDistinctUtil(String s, String t, int i1, int i2, int[][] dp){
if(i2 == t.length()){
return 1; // Successfully matched all characters of t
}
if(i1 >= s.length()){
return 0; // Reached the end of s without matching all of t
}
if(dp[i1][i2] != - 1){
return dp[i1][i2];
}
int distinctSubs = 0;
if(s.charAt(i1) == t.charAt(i2)){
// Use current character of s + don't use it
distinctSubs = numDistinctUtil(s, t, i1 + 1, i2 + 1, dp) + numDistinctUtil(s, t, i1 + 1, i2, dp);
} else{
distinctSubs = numDistinctUtil(s, t, i1 + 1, i2, dp); // Skip current character of s
}
return dp[i1][i2] = distinctSubs;
}
}
2. Tabulation
class Solution {
public int numDistinct(String s, String t) {
int m = s.length();
int n = t.length();
if(m < n){
return 0;
}
int[][] dp = new int[m + 1][n + 1];
// An empty t is a subsequence of any prefix of s
for (int i = 0; i <= m; i++) {
dp[i][0] = 1;
}
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];
}
}
}
return dp[m][n];
}
}
3. Space optimization [2-D array]
class Solution {
public int numDistinct(String s, String t) {
int m = s.length();
int n = t.length();
if (m < n) {
return 0;
}
int[] prev = new int[n + 1];
int[] curr = new int[n + 1];
// Initialize the base case
prev[0] = 1; // An empty t is a subsequence of any prefix of s
for (int i = 1; i <= m; i++) {
curr[0] = 1; // Reset curr[0] for the new row
for (int j = 1; j <= n; j++) {
if (s.charAt(i - 1) == t.charAt(j - 1)) {
curr[j] = prev[j - 1] + prev[j];
} else {
curr[j] = prev[j];
}
}
// Copy curr to prev for the next iteration
prev = curr.clone();
}
return prev[n];
}
}
4. Space optimization [1-D array]
class Solution {
public int numDistinct(String s, String t) {
int m = s.length();
int n = t.length();
if (m < n) {
return 0;
}
int[] prev = new int[n + 1];
// Initialize the base case
prev[0] = 1; // An empty t is a subsequence of any prefix of s
for (int i = 1; i <= m; i++) {
for (int j = n; j >= 1; j--) {
if (s.charAt(i - 1) == t.charAt(j - 1)) {
prev[j] = prev[j - 1] + prev[j];
}
}
}
return prev[n];
}
}