↓Skip to main content
  1. LeetCode/

LeetCode 940: Distinct Subsequences II

·2 mins· ·
LeetCode Hard Dynamic-Programming String
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: hard First Attempt: 2026-09-12

  • Submissions: Accepted (first try)

Approach
#

“Pick or skip each character” counts identical subsequences many times (in "aa", picking either a gives "a").

Group by last character: end[c] = the number of distinct subsequences ending with c. On a new character c:

  • Every current distinct subsequence (sum(end.values()) of them) can have c appended, giving subsequences ending with c.
  • Plus "c" on its own.

These new ones already include every old subsequence ending with c (the old ones extended earlier subsequences, which are all still present), so overwrite end[c] rather than adding.

The answer is sum(end.values()).

My Solution
#

class Solution:
    def distinctSubseqII(self, s: str) -> int:
        MOD = 10 ** 9 + 7
        end = {}                                   # distinct subsequences ending with each character
        for c in s:
            end[c] = (sum(end.values()) + 1) % MOD # append c to all, plus "c" itself
        return sum(end.values()) % MOD

Complexity
#

Time O(26 · n), space O(26).

Mistakes to Avoid
#

  • Overwrite end[c], do not accumulate it: accumulating recounts the old subsequences ending with c.
  • Only non-empty subsequences count, so do not add the empty string.

Interview Explanation
#

I group distinct subsequences by their last character. On character c, appending c to every current distinct subsequence, plus c alone, gives every distinct subsequence ending in c, already including the old ones, so I overwrite. The answer sums the 26 groups. Time O(26n).

Related

LeetCode 1320: Minimum Distance to Type a Word Using Two Fingers
·2 mins
LeetCode Hard Dynamic-Programming State-Machine String
LeetCode 1320 note: after typing word[i], one finger is always on word[i], so the state is only the other finger’s position; dp[other] is the least distance with the other finger at other
LeetCode 902: Numbers At Most N Given Digit Set
·2 mins
LeetCode Hard Dynamic-Programming Digit-Dp Math Binary-Search String
LeetCode 902 note: digit DP with state (pos, tight, started); before starting, a position can be skipped, representing numbers with fewer digits than n
LeetCode 1147: Longest Chunked Palindrome Decomposition
·2 mins
LeetCode Hard Dynamic-Programming Greedy Two-Pointers Rolling-Hash String
LeetCode 1147 note: build strings inward from both ends and cut a pair as soon as they match; cutting early is best, and any leftover middle counts as one chunk
LeetCode 488: Zuma Game
·3 mins
LeetCode Hard Dynamic-Programming Memoization Breadth-First-Search String Stack
LeetCode 488 note: with at most 16 balls on the board and 5 in hand, memoize DFS on the whole (board, hand) state, inserting only before a same-colored ball or between two equal balls
LeetCode 1745: Palindrome Partitioning IV
·2 mins
LeetCode Hard Dynamic-Programming Interval-Dp String
LeetCode 1745 note: build is_pal[i][j] with interval DP, then try both cut points; three palindromic parts means true, O(n^2)
LeetCode 1092: Shortest Common Supersequence
·5 mins
LeetCode Hard Dynamic-Programming String
LeetCode note for Shortest Common Supersequence, rebuilt from the original learning note