InterviewPrepKit

Home / Coding / 2-D Dynamic Programming

Distinct Subsequences

hard Original ↗
Solving tips
  • This is two-string prefix DP: dp[i][j] = number of ways t[:j] appears as a subsequence of s[:i], branching on whether the current characters match.
  • Recurrence: always allow skipping s[i-1] (dp[i-1][j]); when s[i-1]==t[j-1] additionally add the diagonal term dp[i-1][j-1] for using it — add the match term only on equality.
  • Base cases matter: dp[i][0]=1 for all i (empty target matched by deleting everything) but dp[0][j]=0 for j>0.
  • Target O(len(s)*len(t)) time; collapse to a 1-D array of size len(t)+1 swept RIGHT-TO-LEFT so dp[j-1] still holds the previous row's value.

Problem

Given two strings s and t, count the number of distinct ways to delete some (possibly zero) characters from s, without reordering the rest, so that the remaining characters spell exactly t. Two ways are different if they delete a different set of positions. Return that count.

A subsequence keeps characters in their original order but need not be contiguous.

Examples

  • s = "rabbbit", t = "rabbit"3 — three different choices of which b to drop from the three b’s in s produce "rabbit".
  • s = "babgbag", t = "bag"5 — five distinct index-sets of s spell "bag".
  • s = "abc", t = "abcd"0t is longer than s, so it can never be formed.

Constraints

  • 1 <= len(s), len(t) <= 1000 (roughly)
  • Both strings consist of English letters.
  • The answer fits in a 32-bit signed integer.
  • With lengths up to ~1000, an O(len(s)·len(t)) table is the intended complexity; enumerating subsequences (up to 2^len(s)) is impossible.

Think about it first

Hint 1 Walk both strings from the front. Consider the last character of the prefixes you are matching. Whether `s`'s current character equals `t`'s current character decides your options.
Hint 2 Let `dp[i][j]` be the number of ways the first `j` characters of `t` appear as a subsequence of the first `i` characters of `s`. You can always *skip* `s[i-1]` (that gives `dp[i-1][j]`). If `s[i-1] == t[j-1]`, you may additionally *use* it to match `t[j-1]`, adding `dp[i-1][j-1]`.
Hint 3 `dp[i][j] = dp[i-1][j] + (dp[i-1][j-1] if s[i-1]==t[j-1] else 0)`. The base case `dp[i][0] = 1` (the empty `t` is matched exactly one way — delete everything). Since each row needs only the row above, one array of length `len(t)+1` swept right-to-left suffices.
Your workspace Not runnable by design — this is your interview scratchpad. Saved on this device.