Watch 10 video solutions for Distinct Subsequences, a hard level problem involving String, Dynamic Programming. This walkthrough by take U forward has 215,300 views views. Want to try solving it yourself? Practice on FleetCode or read the detailed text solution.
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.rabbbitrabbbitrabbbit
Example 2:
Input: s = "babgbag", t = "bag" Output: 5 Explanation: As shown below, there are 5 ways you can generate "bag" from s.babgbagbabgbagbabgbagbabgbagbabgbag
Constraints:
1 <= s.length, t.length <= 1000s and t consist of English letters.Problem Overview: Given two strings s and t, count how many distinct subsequences of s equal t. A subsequence keeps the original order but may skip characters. The challenge is efficiently counting all valid combinations without generating them explicitly.
Approach 1: Dynamic Programming 2D Table (O(m * n) time, O(m * n) space)
This approach builds a DP table where dp[i][j] represents the number of ways the first i characters of s can form the first j characters of t. Initialize dp[i][0] = 1 because an empty target can always be formed by deleting characters from s. Iterate through both strings: if s[i-1] == t[j-1], you can either use that character (dp[i-1][j-1]) or skip it (dp[i-1][j]). Otherwise, only skipping is possible. This solution is a classic dynamic programming pattern where each state depends on previously computed prefixes.
The DP table effectively counts combinations without constructing subsequences. Each cell aggregates counts from earlier decisions, making it far more efficient than recursion or brute force enumeration.
Approach 2: Dynamic Programming with Space Optimization (O(m * n) time, O(n) space)
The 2D table can be compressed into a single array because each row only depends on the previous one. Maintain a 1D array dp[j] representing the number of ways to build the first j characters of t. Traverse the source string s, and update the DP array from right to left. Reverse iteration is critical: it prevents overwriting values that are still needed for the current iteration.
When s[i] == t[j], update dp[j+1] += dp[j]. This accumulates the number of subsequences that can extend the previous match. The algorithm still processes every pair of characters but reduces memory from O(m*n) to O(n), which matters when strings are large. This technique is common in optimized dynamic programming solutions that depend only on the previous row.
Both approaches rely heavily on prefix relationships within a string. Instead of generating subsequences, you count them using combinational state transitions.
Recommended for interviews: The 2D DP approach is the clearest explanation during interviews. It shows you understand state definition and transition logic. After that, mention the space optimization to reduce memory from O(m*n) to O(n). Interviewers often expect the optimized version for large constraints, but demonstrating the full DP table first proves you understand the underlying recurrence.
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Dynamic Programming 2D Table | O(m * n) | O(m * n) | Best for understanding the full DP state transition and explaining the recurrence during interviews |
| DP with Space Optimization | O(m * n) | O(n) | When memory is constrained or strings are large; same logic but compressed DP state |