Skip to content
AI360Xpert
Beta
Difficulty: Hard2-D Dynamic Programming

Distinct Subsequences

Problem in Plain English

Given a source string and a target string, count how many different ways the target appears as a subsequence of the source, where each way deletes characters while keeping the remaining order.

Problem Statement

Given two strings s and t, return the number of distinct subsequences of s that equal t. A subsequence keeps the relative order of its characters while deleting zero or more characters from the original string.

Two ways are different when they use different index positions in s, even if the matched letters look the same. For example, the three b characters in "rabbbit" create separate ways to match the b characters of "rabbit".

The answer is guaranteed to fit in a 32-bit signed integer.

Constraints

  • 1 <= s.length <= 1000
  • 1 <= t.length <= 1000
  • s and t consist of English letters.
  • The answer fits in a 32-bit signed integer.

Examples

Example 1

Input
s = "rabbbit", t = "rabbit"
Output
3

Use source positions 0 and 1 for r and a, positions 5 and 6 for i and t, then choose b positions (2,3), (2,4), or (3,4). Each increasing index list spells rabbit; these are three distinct embeddings even though their letters coincide.

Example 2

Input
s = "babgbag", t = "bag"
Output
5

Using zero-based indices, the five embeddings are (0,1,3), (0,1,6), (0,5,6), (2,5,6), and (4,5,6). Every triple spells bag and respects source order.

Example 3

Input
s = "a", t = "aa"
Output
0

One source position cannot supply two target characters. Equal letter values do not permit reusing the same index, so a longer target has no embedding.

Intuition

Count choices of source positions, not different spellings. In "rabbbit", choosing any two of the three b positions leaves "rabbit", giving three embeddings. At a source character, skipping it keeps the next target character unchanged; using it advances the target only when the letters match. These disjoint choices add counts. Dynamic programming remembers the number of ways to form each target prefix rather than exploring the same remaining strings repeatedly.

Approaches

Recursive Match or Skip

Solution Details

Reveal Recursive Match or Skip: intuition, complexity, and code

Hints

Hint 1
Count source index choices rather than unique resulting strings; the b positions in Example 1 are interchangeable letters but different choices.
Hint 2
A matching source character can be skipped or used; a mismatching one can only be skipped. What does an exhausted target contribute?
Hint 3
Store counts for target prefix lengths. When adding one source character, which traversal order keeps the old shorter-prefix counts intact?
Hint 4
Cap intermediate counts at the guaranteed final maximum using nonnegative saturation; do not assume shorter-prefix counts fit merely because dp[n] does.

Edge Cases

  • A longer target than source cannot embed; s="a", t="aa" gives 0.
  • Identical strings have one embedding, even with repeated letters: all positions must be used.
  • A missing target letter gives 0 even when other target-prefix counts are huge: s="a" repeated 1000 times, t="a" repeated 500 times followed by "b".
  • English letters are case-sensitive: s="Aa", t="a" has one embedding.
  • Empty target/source states occur inside recursion although public inputs are nonempty; both exhausted must return 1.

Common Mistakes and Interview Tips

  • Ascending 1D updates reuse the current source index, incorrectly giving a positive count for s="a", t="aa".
  • Initializing dp[0] to 0 destroys every count; the empty target has exactly one embedding.
  • Counting only distinct spellings or using a set discards different source-position choices.
  • The final 32-bit guarantee does not protect intermediate prefix counts. A plain int can overflow; a wider fixed integer can still overflow for length 1000. Use proven saturation or arbitrary precision with an adjusted complexity analysis.
  • The recursive approach intentionally has no memoization and is infeasible for large branching inputs; explain the bottleneck before recommending the DP.
  • Python default recursion limits can fail on 1000 source characters. The published recursive snippet temporarily reserves room and restores the prior setting; use iterative DP for arbitrary caller depths.

Key Takeaway

Counting subsequence embeddings partitions choices into skip and match groups. Compressing prefix DP to one row requires backward updates so dependencies still refer to the previous source prefix; arithmetic must preserve counts even when irrelevant intermediate states are huge.