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.
We use a 2D DP table where `dp[i][j]` represents the number of distinct subsequences of `s[0..i-1]` which forms `t[0..j-1]`. The size of the table is `(m+1)x(n+1)` where `m` is the length of `s` and `n` is the length of `t`.
Initialize `dp[0][0]` to 1 because an empty string is a subsequence of itself, and `dp[i][0]` to 1 for all `i`, because an empty `t` is a subsequence of any prefix of `s`. Then, for each character `s[i-1]` and `t[j-1]`, update the DP table as follows:
This C code uses a two-dimensional array `dp` where dp[i][j] contains the number of ways the first `i` characters of `s` can form the first `j` characters of `t`. We initialize the first column (except `dp[0][0]`) to 1 because the empty string `t` is a subsequence of any string `s`. We fill the DP table according to the conditions based on whether the current characters of `s` and `t` match or not, then return the value at dp[m][n], which contains the number of distinct subsequences.
C++
Java
Python
C#
JavaScript
Time Complexity: O(m * n), where `m` is the length of `s` and `n` is the length of `t`.
Space Complexity: O(m * n) for the DP table.
We can optimize the space complexity by observing that to calculate `dp[i][j]`, we only need values from the previous row. Thus, we can use a 2-row approach, maintaining only `previous` and `current` arrays to save space. This reduces the space complexity to O(n), where `n` is the length of `t`.
The transition is similar to the 2D approach but only updates the necessary parts of the `current` array based on the `previous` row.
This C function reduces space usage by utilizing two arrays, alternating between them to store the current and previous results. The modulo operation helps alternate between using `previous` and `current`, simplifying the 2D structure to two 1D arrays.
C++
Java
Python
C#
JavaScript
Time Complexity: O(m * n), where `m` is the length of `s` and `n` is the length of `t`.
Space Complexity: O(n), using only two rows for DP storage.
| Approach | Complexity |
|---|---|
| Dynamic Programming 2D Table | Time Complexity: O(m * n), where `m` is the length of `s` and `n` is the length of `t`. |
| Dynamic Programming with Space Optimization | Time Complexity: O(m * n), where `m` is the length of `s` and `n` is the length of `t`. |
| 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 |
DP 32. Distinct Subsequences | 1D Array Optimisation Technique 🔥 • take U forward • 215,300 views views
Watch 9 more video solutions →Practice Distinct Subsequences with our built-in code editor and test cases.
Practice on FleetCodePractice this problem
Open in Editor