Numbers At Most N Given Digit Set

HardDigit DP · Combinatorics🧩 Digit DPLeetCode #902 ↗Updated

Problem

You get a sorted array digits of distinct characters from '1' to '9', and an integer n. Any digit may be reused any number of times. Count how many positive integers you can write using only these digits that are ≤ n.
Inputdigits = ["1","3","5","7"], n = 100Output20
Inputdigits = ["1","4","9"], n = 1000000000Output29523
Inputdigits = ["7"], n = 8Output1

1 ≤ digits.length ≤ 9  ·  digits are distinct, sorted, in '1'..'9'  ·  1 ≤ n ≤ 109

Try it yourself

Java
class Solution {
    public int atMostNGivenDigitSet(String[] digits, int n) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
Split by length. Every number shorter than n is automatically smaller: that is klen choices per length. For numbers of the same length, walk n's digits left to right: a smaller digit here frees all later positions; an equal digit keeps you “tight”; no match means stop.
PatternDigit DP

Instinct Count numbers in [L, R] (R up to 10^9 or 10^18) whose digits obey a rule - build the number digit by digit with a "still tight to N" flag.

Memory hack Walk the digits on a leash - stay tight to N or break free, and once free you never go back. Remember PTLS - Position, Tight, Leading zero, State.

Open the Digit DP guide →

Approaches

Brute ForceGenerate Every Number (DFS)

Time O(answer)Space O(log n)

Build numbers by appending one allowed digit at a time to a prefix. Each prefix that is still ≤ n counts once and is extended further. Since the digits are sorted, the first digit that overshoots lets us stop the loop.

Java
public int atMostNGivenDigitSet(String[] digits, int n) {
    return countFrom(digits, 0L, n);
}

// counts all valid numbers that strictly extend the prefix 'cur'
private int countFrom(String[] digits, long cur, int n) {
    int total = 0;
    for (String d : digits) {
        long next = cur * 10 + (d.charAt(0) - '0');
        if (next > n) break; // sorted digits: the rest are even bigger
        total += 1 + countFrom(digits, next, n);
    }
    return total;
}

Correct and obvious, but the answer can be ~4×108 — far too slow.

At a glance

LevelApproachTimeSpace
Brute ForceGenerate Every Number (DFS)O(answer)O(log n)
BetterDigit DP with Memo (pos, tight, started)O(L · 10)O(L)
OptimalCount by Length + Prefix WalkO(L · k)O(L)
Common pitfalls
  • Forgetting numbers that are shorter than n — they are always valid.
  • Adding +1 for n itself even when the walk stopped early.
  • Continuing the walk after a digit of n is not in the set — you must return.
Interview tips
  • Start from “count shorter numbers first” — it makes the rest feel natural.
  • Name the tight/free idea: once you go below n at some digit, the tail is unrestricted.
  • Mention the general digit-DP template for variants (digit sums, no repeated digits, etc.).
Pattern
Digit DP / prefix counting → count integers ≤ N with a digit-level rule; process N's digits left to right with a tight flag.
My notes saved in this browser