Distinct Subsequences
HardPrompt
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:
<strong><u>rabb</u></strong>b<strong><u>it</u></strong>Example 2:
<strong><u>ba</u></strong>b<u><strong>g</strong></u>bag
Constraints:
1 <= s.length, t.length <= 1000sandtconsist of English letters.
Approaches
4 approaches with complexity analysis and trade-offs.
This approach uses a simple recursive function to solve the problem. The function solve(i, j) calculates the number of distinct subsequences of s starting from index i that match t starting from index j.
Algorithm
- Define a recursive function
solve(s, t, i, j). - Base Case 1: If
jequals the length oft, it means we have successfully formedt. Return 1. - Base Case 2: If
iequals the length ofsbutjis less than the length oft, it's impossible to formt. Return 0. - If
s.charAt(i)is equal tot.charAt(j), the result is the sum of two recursive calls:solve(s, t, i + 1, j + 1)(matching the characters) andsolve(s, t, i + 1, j)(skippings.charAt(i)). - If
s.charAt(i)is not equal tot.charAt(j), we must skips.charAt(i). The result issolve(s, t, i + 1, j).
Walkthrough
The core idea is to explore all possibilities. For each character s[i] in the source string s, we compare it with the character t[j] in the target string t.
-
If
s[i]matchest[j], we have two choices:- We can use
s[i]to form the subsequence. In this case, we need to find the number of ways to form the rest oft(i.e.,t[j+1:]) from the rest ofs(i.e.,s[i+1:]). - We can skip
s[i]and try to find a match fort[j]later ins. In this case, we need to find the number of ways to formt[j:]froms[i+1:]. The total number of ways is the sum of these two possibilities.
- We can use
-
If
s[i]does not matcht[j], we have no choice but to skips[i]and try to find a match fort[j]in the rest ofs(i.e.,s[i+1:]).
This logic is implemented recursively. The base cases for the recursion are:
- If we have successfully matched all characters of
t(i.e.,jreaches the end oft), we have found one valid subsequence. We return 1. - If we have run out of characters in
s(i.e.,ireaches the end ofs) but still have characters intto match, it's impossible to form the subsequence. We return 0.
class Solution { public int numDistinct(String s, String t) { return solve(s, t, 0, 0); } private int solve(String s, String t, int i, int j) { // Base case 1: If we have found all characters of t, it's a valid subsequence. if (j == t.length()) { return 1; } // Base case 2: If we have run out of characters in s but not in t. if (i == s.length()) { return 0; } // If characters match, we have two options: // 1. Match s[i] with t[j] and look for the rest of t in the rest of s. // 2. Skip s[i] and look for t[j] in the rest of s. if (s.charAt(i) == t.charAt(j)) { return solve(s, t, i + 1, j + 1) + solve(s, t, i + 1, j); } else { // If characters don't match, we must skip s[i]. return solve(s, t, i + 1, j); } }}Complexity
Time
O(2^m)
Space
O(m + n)
Trade-offs
Pros
Simple and easy to understand the logic.
Direct translation of the problem's recursive definition.
Cons
Extremely inefficient due to a large number of overlapping subproblems.
Will result in a 'Time Limit Exceeded' (TLE) error for larger inputs.
Solutions
Solution
class Solution {public int numDistinct(String s, String t) { int n = t.length(); int[] f = new int[n + 1]; f[0] = 1; for (char a : s.toCharArray()) { for (int j = n; j > 0; --j) { char b = t.charAt(j - 1); if (a == b) { f[j] += f[j - 1]; } } } return f[n]; }}Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.