CodeMosa

Master LeetCode Patterns

Digit DP

Count numbers with constrained digits using tight/loose states

Time: O(d·S)
Space: O(d·S)

What is Digit DP?

#
Definition: Traverse digits with a tight flag up to N while carrying auxiliary state (e.g., prev digit or sum) to count valid numbers.

Core Idea

#

Traverse digits most-significant to least with a 'tight' flag and memoize (pos, tight, state...).

When to Use

#

Use for counting numbers ≤ N with properties (e.g., no consecutive ones, digit sums).

How Digit DP works

#

Pick digits up to the bound when tight; memoize (i, tight, state...) and handle leading zeros to avoid double counts.

  • Count ≤ N
  • Digit constraints
  • Tight flag

General Recognition Cues

#
General indicators that this pattern might be applicable
  • Count ≤ N
  • Digit constraints
  • Tight flag

Code Templates

#
Traverse digits MSB→LSB with a tight flag and problem-specific state; memoize on (i, tight, ...). Handle leading zeros carefully.
# String Algorithms Template (KMP)
def kmp_search(text, pattern):
    if not pattern: return 0
    lps=[0]*len(pattern)
    j=0
    for i in range(1,len(pattern)):
        while j>0 and pattern[i]!=pattern[j]: j=lps[j-1]
        if pattern[i]==pattern[j]: j+=1; lps[i]=j
    j=0
    for i,ch in enumerate(text):
        while j>0 and ch!=pattern[j]: j=lps[j-1]
        if ch==pattern[j]: j+=1
        if j==len(pattern): return i-j+1
    return -1

Pattern Variants & Approaches

#
Different methodologies and implementations for this pattern
1

Tight/Loose States

#

Constrain next digit when tight

When to Use This Variant
  • Upper bound N
Use Case
Counting with cap
Advantages
  • Memoized recursion
Implementation
from functools import lru_cache
def count_no_consec_ones(n):
    s = bin(n)[2:]
    @lru_cache(None)
    def dp(i, tight, prev1):
        if i == len(s): return 1
        up = int(s[i]) if tight else 1
        total = 0
        for d in range(up + 1):
            if prev1 and d == 1: continue
            total += dp(i+1, tight and d==up, d==1)
        return total
    return dp(0, True, False)
2

Property Tracking

#

Carry state like prev digit/sum

When to Use This Variant
  • No consecutive 1s
Use Case
Pattern counts
Advantages
  • Flexible
Implementation
from functools import lru_cache
def count_digits_sum_leq(n, target):
    s=str(n)
    @lru_cache(None)
    def dp(i, tight, sum_):
        if i==len(s): return 1 if sum_<=target else 0
        up = int(s[i]) if tight else 9
        total=0
        for d in range(up+1):
            total += dp(i+1, tight and d==up, sum_+d)
        return total
    return dp(0, True, 0)

Common Pitfalls

#
Watch out for these common mistakes
  • Leading zeros handling
  • Tight transitions
  • State definition

Example Problems

#
Classic LeetCode problems using this pattern

Complexity Analysis

#
Time Complexity
O(d·S)

Digits times state size.

Space Complexity
O(d·S)

Memo table size.

Ready to test your knowledge?

Test your pattern recognition with interactive questions