Talentd
FleetCode
Make and follow sheets.Sign in

Numbers At Most N Given Digit Set solution and explanation

HardArrayBinary SearchDynamic ProgrammingMath8 min read45.9% acceptanceUpdated 9 Apr 2026
Numbers At Most N Given Digit Set 🔥| Leetcode 902 | MathAyushi Sharma · 20:46 · 2K viewsWatch on YouTube
9 more videos on this problem
  1. Numbers At Most N Given Digit Set 🔥| Leetcode 902 | MathAyushi Sharma · 20:46 · 2K views
  2. 花花酱 LeetCode 902. Numbers At Most N Given Digit Set - 刷题找工作 EP225Hua Hua · 12:46 · 2K views
  3. LeetCode 902. Numbers At Most N Given Digit Set - Nov 21st - November LeetCoding Challenge -GoMasterGoMaster Coding Interviews · 17:17 · 2K views
  4. L-05. Digit DP | Numbers At Most N Given Digit Set | Leetcode 902 | Recursive + MemoizationWhy Not DP [By Piyush Raj] · 30:49 · 2K views
  5. Numbers At Most N Given Digit Set | LeetCode 902 | Coders CampCoders Camp · 12:10 · 1K views
  6. LeetCode 902. Numbers At Most N Given Digit SetHappy Coding · 21:13 · 1K views
  7. Numbers At N Given Digit Set | Leetcode November Challenge Day 21 | Leetcode 902Coding Decoded · 14:10 · 1K views
  8. Numbers At Most N Given Digit Set | Leetcode 902 | Live coding session 🔥🔥🔥Coding Decoded · 0:54 · 1K views
  9. Daily Leetcode #235: Nov 21, 2020 - 902. Numbers At Most N Given Digit SetProgramming Live with Larry · 20:37 · 436 views
  10. 【每日一题】902. Numbers At Most N Given Digit Set, 1/7/2020Huifeng Guan · 15:30 · 408 views

The problem

Given an array of digits which is sorted in non-decreasing order. You can write numbers using each digits[i] as many times as we want. For example, if digits = ['1','3','5'], we may write numbers such as '13', '551', and '1351315'.

Return the number of positive integers that can be generated that are less than or equal to a given integer n.

Example 1:

Input: digits = ["1","3","5","7"], n = 100
Output: 20
Explanation: 
The 20 numbers that can be written are:
1, 3, 5, 7, 11, 13, 15, 17, 31, 33, 35, 37, 51, 53, 55, 57, 71, 73, 75, 77.

Example 2:

Input: digits = ["1","4","9"], n = 1000000000
Output: 29523
Explanation: 
We can write 3 one digit numbers, 9 two digit numbers, 27 three digit numbers,
81 four digit numbers, 243 five digit numbers, 729 six digit numbers,
2187 seven digit numbers, 6561 eight digit numbers, and 19683 nine digit numbers.
In total, this is 29523 integers that can be written using the digits array.

Example 3:

Input: digits = ["7"], n = 8
Output: 1

Constraints:

  • 1 <= digits.length <= 9
  • digits[i].length == 1
  • digits[i] is a digit from '1' to '9'.
  • All the values in digits are unique.
  • digits is sorted in non-decreasing order.
  • 1 <= n <= 109

Approach overview

Problem Overview: You are given a set of allowed digits and an integer N. Count how many positive integers less than or equal to N can be formed using only those digits, where digits can be reused any number of times.

Approach 1: Backtracking Enumeration (Exponential)

This method generates all valid numbers using recursive backtracking. Start with an empty number and repeatedly append each digit from the allowed set. Stop when the constructed number exceeds N. Every valid number encountered is counted. The approach directly explores the search space of possible numbers and uses simple recursion with pruning when values exceed N. Time complexity is roughly O(k^d) where k is the number of digits and d is the number of digits in N. Space complexity is O(d) due to recursion depth. This approach is easy to implement but becomes slow when N has many digits.

Approach 2: Digit Dynamic Programming (Optimal)

The optimal solution uses digit DP and combinatorics to count valid numbers without enumerating them. First count all numbers with fewer digits than N. If the digit set size is k and the length of N is d, then there are k^1 + k^2 + ... + k^(d-1) valid numbers of smaller length. Next process the digits of N from left to right. For each position, count how many digits from the allowed set are smaller than the current digit of N. Each such choice contributes k^(remaining positions) possibilities. If the current digit of N is not in the digit set, the process stops early because larger prefixes would exceed N. If all digits match valid choices, include N itself. This approach uses ideas from dynamic programming, math, and array processing. Time complexity is O(d * k) and space complexity is O(1).

Recommended for interviews: Interviewers expect the digit DP counting approach. Brute-force backtracking shows you understand the search space, but it does not scale. The DP/combinatorics method demonstrates strong reasoning about digit positions, prefix constraints, and counting techniques—skills frequently tested in hard problems involving dynamic programming and numeric strings.

Approach 1: Backtracking Approach

This approach uses backtracking to consider all possible numbers that can be formed using the given digits. It constructs numbers digit by digit and checks if they are valid (less than or equal to n). If a number reaches the length of n, it checks if it should continue further based on the current digit comparison.

def atMostNGivenDigitSet(digits, n):
    str_n = str(n)
    L = len(str_n)
    count = 0
    # Count numbers with length less than that of n
    for i in range(1, L):
        count += len(digits) ** i
    
    # Count numbers with the same length as n
    def backtrack(pos, isTight):
        if pos == L:
            return 1
        validNumbers = 0
        for digit in digits:
            if digit < str_n[pos]:
                validNumbers += len(digits) ** (L - pos - 1)
            elif digit == str_n[pos]:
                validNumbers += backtrack(pos + 1, True)
        return validNumbers
    count += backtrack(0, True)    
    return count

digits = ['1', '3', '5', '7']
n = 100
print(atMostNGivenDigitSet(digits, n))
function atMostNGivenDigitSet(digits, n) {
    const strN = n.toString();
    const L = strN.length;
    let count = 0;
    // Count numbers with length less than that of n
    for (let i = 1; i < L; i++) {
        count += Math.pow(digits.length, i);
    }
    
    // Count numbers with the same length as n
    function backtrack(pos, isTight) {
        if (pos === L) return 1;
        let validNumbers = 0;
        for (let digit of digits) {
            if (digit < strN[pos]) {
                validNumbers += Math.pow(digits.length, L - pos - 1);
            } else if (digit === strN[pos]) {
                validNumbers += backtrack(pos + 1, true);
            }
        }
        return validNumbers;
    }
    count += backtrack(0, true);
    return count;
}

const digits = ['1', '3', '5', '7'];
const n = 100;
console.log(atMostNGivenDigitSet(digits, n));

In this solution, the function converts `n` to a string and checks each digit position recursively. It first adds up all possible numbers with fewer digits. While iterating through each position, it recursively validates if combinations up to that point are within the allowable range, incrementing the valid count as appropriate.

Complexity

Time Complexity: O((log n) * m)
Space Complexity: O(log n)

Try this approach in the editor

Approach 2: Dynamic Programming Approach

This approach uses dynamic programming to pre-compute the number of valid numbers at each digit position. It updates a dp array to track possible numbers we can form up to each digit, considering all combinations of digits in the set.

import java.util.*;

public class DigitSet {
    public int atMostNGivenDigitSet(String[] digits, int n) {
        String strN = Integer.toString(n);
        int L = strN.length(), m = digits.length;
        int[] dp = new int[L + 1];
        dp[L] = 1;

        for (int i = L - 1; i >= 0; --i) {
            for (String d : digits) {
                if (d.charAt(0) < strN.charAt(i)) {
                    dp[i] += Math.pow(m, L - i - 1);
                } else if (d.charAt(0) == strN.charAt(i)) {
                    dp[i] += dp[i + 1];
                }
            }
        }

        for (int i = 1; i < L; ++i) {
            dp[0] += Math.pow(m, i);
        }

        return dp[0];
    }

    public static void main(String[] args) {
        String[] digits = {"1", "3", "5", "7"};
        int n = 100;
        DigitSet digitSet = new DigitSet();
        System.out.println(digitSet.atMostNGivenDigitSet(digits, n));
    }
}
#include <iostream>
#include <vector>
#include <string>
#include <cmath>
using namespace std;

int atMostNGivenDigitSet(vector<string>& digits, int n) {
    string str_n = to_string(n);
    int L = str_n.size(), m = digits.size();
    vector<int> dp(L + 1, 0);
    dp[L] = 1;
    
    for (int i = L - 1; i >= 0; --i) {
        for (string& d : digits) {
            if (d[0] < str_n[i])
                dp[i] += pow(m, L - i - 1);
            else if (d[0] == str_n[i])
                dp[i] += dp[i + 1];
        }
    }
    
    for (int i = 1; i < L; ++i)
        dp[0] += pow(m, i);
    
    return dp[0];
}

int main() {
    vector<string> digits = {"1", "3", "5", "7"};
    int n = 100;
    cout << atMostNGivenDigitSet(digits, n) << endl;
    return 0;
}

This Java solution implements a similar strategy using dynamic programming. The dp array is utilized to calculate and store valid numbers incrementally for each digit level.

Complexity

Time Complexity: O(mlog n)
Space Complexity: O(log n)

Try this approach in the editor

Approach 3: Digit DP

This problem essentially asks for the number of positive integers that can be generated from the digits in digits within the given range [l, .., r]. The count depends on the number of digits and the value of each digit. We can solve this problem using the Digit DP approach. In Digit DP, the size of the number has little impact on the complexity.

For the range [l, .., r] problem, we generally convert it to the problem of [1, .., r] and then subtract the result of [1, .., l - 1], i.e.,

$ ans = sum_{i=1}^{r} ans_i - sum_{i=1}^{l-1} ans_i

However, for this problem, we only need to find the value for the range [1, .., r].

Here, we use memoization to implement Digit DP. We start searching from the top, get the number of solutions at the bottom, and return the answers layer by layer until we get the final answer from the starting point.

The basic steps are as follows:

We convert the number n into a string s and denote the length of the string s as m.

Next, we design a function dfs(i, lead, limit) to represent the number of solutions from the current i-th digit to the last digit of the string. Here:

  • The integer i represents the current position in the string s.
  • The boolean lead indicates whether the current number contains only leading zeros.
  • The boolean limit indicates whether the current position is restricted by the upper bound.

The function executes as follows:

If i is greater than or equal to m, it means we have processed all digits. If lead is true, it means the current number is a leading zero, and we should return 0. Otherwise, we should return 1.

Otherwise, we calculate the upper bound up. If limit is true, then up is the digit corresponding to s[i]. Otherwise, up is 9.

Then, we enumerate the current digit j in the range [0, up]. If j is 0 and lead is true, we recursively calculate dfs(i + 1, true, limit \wedge j = up). Otherwise, if j is in digits, we recursively calculate dfs(i + 1, false, limit \wedge j = up). We accumulate all the results as the answer.

Finally, we return dfs(0, true, true).

The time complexity is O(log n times D), and the space complexity is O(log n). Here, D = 10$.

Similar problems:

function atMostNGivenDigitSet(digits: string[], n: number): number {
    const s = n.toString();
    const m = s.length;
    const f: number[] = Array(m).fill(-1);
    const nums = new Set<number>(digits.map(d => parseInt(d)));
    const dfs = (i: number, lead: boolean, limit: boolean): number => {
        if (i >= m) {
            return lead ? 0 : 1;
        }
        if (!lead && !limit && f[i] !== -1) {
            return f[i];
        }
        const up = limit ? +s[i] : 9;
        let ans = 0;
        for (let j = 0; j <= up; ++j) {
            if (!j && lead) {
                ans += dfs(i + 1, true, limit && j === up);
            } else if (nums.has(j)) {
                ans += dfs(i + 1, false, limit && j === up);
            }
        }
        if (!lead && !limit) {
            f[i] = ans;
        }
        return ans;
    };
    return dfs(0, true, true);
}
func atMostNGivenDigitSet(digits []string, n int) int {
	s := strconv.Itoa(n)
	m := len(s)
	f := make([]int, m)
	for i := range f {
		f[i] = -1
	}
	nums := map[int]bool{}
	for _, d := range digits {
		x, _ := strconv.Atoi(d)
		nums[x] = true
	}
	var dfs func(i int, lead, limit bool) int
	dfs = func(i int, lead, limit bool) int {
		if i >= m {
			if lead {
				return 0
			}
			return 1
		}
		if !lead && !limit && f[i] != -1 {
			return f[i]
		}
		up := 9
		if limit {
			up = int(s[i] - '0')
		}
		ans := 0
		for j := 0; j <= up; j++ {
			if j == 0 && lead {
				ans += dfs(i+1, true, limit && j == up)
			} else if nums[j] {
				ans += dfs(i+1, false, limit && j == up)
			}
		}
		if !lead && !limit {
			f[i] = ans
		}
		return ans
	}
	return dfs(0, true, true)
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Backtracking Approach

Time Complexity: O((log n) * m)
Space Complexity: O(log n)

Dynamic Programming Approach

Time Complexity: O(mlog n)
Space Complexity: O(log n)

Digit DP–

Complexity analysis

ApproachTimeSpaceWhen to Use
Backtracking EnumerationO(k^d)O(d)When exploring the search space conceptually or when N is small
Digit Dynamic Programming / CombinatoricsO(d * k)O(1)General case and interview solution for large N

Frequently asked questions

Is Numbers At Most N Given Digit Set easy or hard?

Numbers At Most N Given Digit Set is classified as a hard problem on LeetCode. The difficulty comes from recognizing the digit DP pattern and converting the constraint "≤ N" into prefix-based counting instead of brute-force generation.

Numbers At Most N Given Digit Set Python/Java solution

Python implementations often use recursion or backtracking for the brute-force version, while optimized solutions rely on digit DP logic. Java and C++ implementations typically compute powers of the digit count and iterate through the digits of N to accumulate valid combinations in O(d * k) time.

How to solve Numbers At Most N Given Digit Set in O(n)?

Treat N as a digit string and process it from left to right. First count all numbers with fewer digits using k^length combinations. Then for each digit position, count how many allowed digits are smaller than the current digit of N and add k^(remaining positions). Stop when a digit in N is not available in the digit set. This yields an O(d * k) solution.

What is the best approach for Numbers At Most N Given Digit Set?

Digit dynamic programming combined with combinatorics is the best approach. It counts valid numbers by analyzing each digit position of N and calculating how many prefixes can be formed using the allowed digits. This avoids generating every number explicitly and runs in O(d * k) time, where d is the number of digits in N and k is the size of the digit set.

Is Numbers At Most N Given Digit Set asked at Google/Amazon/Meta?

Digit DP and combinatorial counting problems similar to this one appear in interviews at companies like Google, Amazon, and Meta. They test the ability to reason about digit constraints, prefix comparisons, and dynamic counting rather than brute-force enumeration.

What data structure is used in Numbers At Most N Given Digit Set?

The solution mainly uses arrays or sets to store the allowed digits and string processing for the digits of N. The key technique is digit dynamic programming, which tracks valid prefixes and counts combinations mathematically.

What is the time complexity of Numbers At Most N Given Digit Set?

The optimal digit DP solution runs in O(d * k) time, where d is the number of digits in N and k is the size of the digit set. Space complexity is O(1) because only a few counters and digit comparisons are required. A brute-force backtracking approach can take O(k^d) time.

Comments

Now write it yourselfClose this page and solve Numbers At Most N Given Digit Set in the editor, without looking.
Practise Numbers At Most N Given Digit Set