AlgoMaster Logo

Numbers At Most N Given Digit Set

hardFrequency6 min readUpdated June 23, 2026

Understanding the Problem

We are given a set of allowed digits (each between '1' and '9'), and we need to count how many positive integers up to n can be formed using only those digits. Each digit can be reused as many times as we want. So if digits = ["1","3"], we can form 1, 3, 11, 13, 31, 33, 111, 113, and so on.

This is a counting problem with two distinct parts. First, any number with fewer digits than n is automatically less than n, so we can count all of those at once. Second, for numbers with the same number of digits as n, we count only those that do not exceed n. The second part is a digit-by-digit comparison against n, the core of digit dynamic programming.

Key Constraints:

  • 1 <= n <= 10^9 → n has at most 10 digits. Any approach that processes digit-by-digit is very efficient.
  • 1 <= digits.length <= 9 → The digit set is small. We can iterate over it freely at each position.
  • digits[i] is from '1' to '9' → No zero in the digit set. Every combination of allowed digits forms a valid positive integer, so there are no leading-zero cases to exclude.

Approach 1: Math (Counting by Number of Digits)

Intuition

Instead of generating numbers one by one, count them with arithmetic. The valid numbers split into two groups by length.

Part 1: Numbers with fewer digits than n. If n has L digits, then any valid number with 1 digit, 2 digits, ..., or L-1 digits is automatically less than n. For k-digit numbers, each of the k positions can hold any of the d allowed digits, and since none of them is '0' there is no leading-zero case. That gives d^k valid numbers of exactly k digits.

Part 2: Numbers with exactly L digits. Process the digits of n from left to right. At position i, count the allowed digits strictly less than n's digit at position i. Choosing one of those commits the number to being smaller than n no matter what follows, so the remaining positions can hold any allowed digit. If n's digit at position i is itself in the allowed set, match it and move to position i+1 with the number still tied to n's prefix. If it is not in the allowed set, no L-digit valid number can share this prefix, so stop.

If every digit of n matches an allowed digit, then n itself is valid, so add 1.

Algorithm

  1. Convert n to a string S of length L. Let d = digits.length.
  2. Initialize count = 0.
  3. For k from 1 to L-1, add d^k to count. These are all valid numbers shorter than n.
  4. For each position i from 0 to L-1:
    • Count how many digits in the allowed set are strictly less than S[i]. Call this less.
    • Add less * d^(L-1-i) to count.
    • If S[i] is not in the allowed set, stop.
    • If S[i] is in the allowed set, continue to the next position.
  5. If we processed all L positions without stopping, add 1 (the number n itself is valid).
  6. Return count.

Example Walkthrough

1n=100, S="100", L=3, d=4, digits={1,3,5,7}
0
1
1
0
2
0
1/7

Code

This approach uses floating-point Math.pow, which can return a value slightly off from the true integer power and corrupt the count after casting. The next approach precomputes powers with integer arithmetic and states the same counting logic as an explicit DP recurrence.

Approach 2: Digit DP (Optimal)

Intuition

The same counting logic restates as a dynamic programming recurrence that processes n from right to left. Define dp[i] as the number of L-digit valid numbers whose first i digits exactly match n's, counting only the completions of positions i through L-1 that keep the number at most n.

The recurrence: at position i, each allowed digit less than S[i] fixes the number below n and leaves the remaining L-1-i positions free, contributing d^(L-1-i). An allowed digit equal to S[i] keeps the prefix tied to n, so its completions are counted by dp[i+1]. Digits greater than S[i] contribute nothing.

The base case is dp[L] = 1: matching all L digits of n means n itself is one valid number. Numbers shorter than n are counted separately, the same as in Approach 1.

Algorithm

  1. Convert n to string S of length L. Let d = digits.length.
  2. Precompute powers: pow[i] = d^i for i from 0 to L using integer arithmetic.
  3. Compute dp from right to left:
    • dp[L] = 1 (base case: matched all digits of n).
    • For i from L-1 down to 0:
      • For each allowed digit less than S[i]: add pow[L-1-i].
      • For each allowed digit equal to S[i]: add dp[i+1].
  4. The answer for same-length numbers is dp[0].
  5. Add shorter numbers: sum of pow[1] through pow[L-1].
  6. Return the total.

Example Walkthrough

1S="573", L=3, d=4. Initialize dp[3]=1 (base case: matched all digits)
0
0
1
0
2
0
3
1
base
1/6

Code