Count Special Integers
HARDDescription
We call a positive integer special if all of its digits are distinct.
Given a positive integer n, return the number of special integers that belong to the interval [1, n].
Example 1:
Input: n = 20 Output: 19 Explanation: All the integers from 1 to 20, except 11, are special. Thus, there are 19 special integers.
Example 2:
Input: n = 5 Output: 5 Explanation: All the integers from 1 to 5 are special.
Example 3:
Input: n = 135 Output: 110 Explanation: There are 110 integers from 1 to 135 that are special. Some of the integers that are not special are: 22, 114, and 131.
Constraints:
1 <= n <= 2 * 109
Approaches
Checkout 2 different approaches to solve Count Special Integers. Click on different approaches to view the approach and algorithm in detail.
Digit DP with Combinatorics
A much more efficient method is to use digit dynamic programming, which builds the count based on the digits of n. Instead of checking every number, we can count the number of valid special integers mathematically. We can count the special integers with fewer digits than n and then count the special integers with the same number of digits as n but are less than or equal to n.
Algorithm
The problem is to count special numbers up to n. This can be solved using digit dynamic programming and combinatorics. Let S be the string representation of n and L be its length.
The count is divided into two parts:
-
Count special numbers with fewer digits than
n:- Iterate for each length
dfrom 1 toL-1. - For a
d-digit number, the first digit has 9 choices (1-9). The remainingd-1digits are a permutation ofd-1digits chosen from the 9 remaining available digits (0-9 excluding the first digit). - The count for length
dis9 * P(9, d-1), whereP(m, k)is the number of k-permutations of m. - Sum these counts for all
d < L.
- Iterate for each length
-
Count special numbers with the same number of digits as
nand are less than or equal ton:- Iterate through the digits of
nfrom left to right (indexifrom 0 toL-1). - Maintain a set of digits
seenin the prefix. - At each position
i, consider placing a digitdthat is smaller than the digitn[i]. - For each such valid
d(not 0 for the first position and not inseen), the remainingL-1-ipositions can be filled inP(10 - (i+1), L-1-i)ways. Add this to the total count. - After checking smaller digits, check the digit
n[i]itself. Ifn[i]is already inseen, it meansnand any other number with this prefix is not special. We must stop and return the current count. - If
n[i]is not inseen, add it toseenand proceed to the next positioni+1.
- Iterate through the digits of
-
Final check for
n:- If the loop completes, it means
nitself is a special number. Increment the final count by 1.
- If the loop completes, it means
Let's illustrate with n = 135. The string is S = "135" and length L = 3.
Part 1: Count special numbers with length < 3
- 1-digit numbers: 9 (1-9).
- 2-digit numbers: The first digit has 9 choices (1-9). The second has 9 choices (0-9, excluding the first). Total:
9 * 9 = 81. - Total for length < 3:
9 + 81 = 90.
Part 2: Count 3-digit special numbers <= 135
- We iterate through
S = "135". - Position 0 (hundreds):
S[0] = '1'. We can't place a smaller digit (since it would have to be 0, which is not allowed as the first digit). So we must place '1'. Mark '1' as seen. - Position 1 (tens):
S[1] = '3'. We can place digits smaller than 3.- Try
d = 0: '0' is not seen. We form10_. The last digit has 8 choices (0-9, excluding 1 and 0). Add 8 to count. - Try
d = 2: '2' is not seen. We form12_. The last digit has 8 choices. Add 8 to count. - Now, we must place '3'. Mark '3' as seen.
- Try
- Position 2 (ones):
S[2] = '5'. We can place digits smaller than 5.- Try
d = 0, 2, 4(1 and 3 are seen). For each, we form130,132,134. These are 3 numbers. Add 3 to count.
- Try
- The loop finishes. Since
135itself has distinct digits, we add 1 for it. - Total for 3-digit numbers:
8 + 8 + 3 + 1 = 20.
Grand Total: 90 + 20 = 110.
Here is the code for this approach:
class Solution {
public int countSpecialNumbers(int n) {
String s = String.valueOf(n);
int L = s.length();
int res = 0;
// Count special numbers with length < L
for (int d = 1; d < L; d++) {
res += 9 * permutations(9, d - 1);
}
// Count special numbers with length L and <= n
boolean[] seen = new boolean[10];
for (int i = 0; i < L; i++) {
int digit = s.charAt(i) - '0';
for (int d = (i == 0) ? 1 : 0; d < digit; d++) {
if (!seen[d]) {
res += permutations(10 - (i + 1), L - 1 - i);
}
}
if (seen[digit]) {
return res; // Duplicate digit found in n's prefix
}
seen[digit] = true;
}
// If we reach here, n itself is a special number
res++;
return res;
}
// Calculates P(m, n) = m! / (m-n)!
private int permutations(int m, int n) {
if (n > m) return 0;
int res = 1;
for (int i = 0; i < n; i++) {
res *= (m - i);
}
return res;
}
}
Complexity Analysis
Pros and Cons
- Extremely efficient and fast, easily passing the given constraints.
- The time complexity depends only on the number of digits in
n, not its magnitude.
- The logic is more complex than the brute-force approach.
- Requires careful handling of edge cases, like the first digit not being zero and tracking used digits.
Code Solutions
Checking out 3 solutions in different languages for Count Special Integers. Click on different languages to view the code.
class Solution { public int countSpecialNumbers ( int n ) { List < Integer > digits = new ArrayList <>(); while ( n != 0 ) { digits . add ( n % 10 ); n /= 10 ; } int m = digits . size (); int ans = 0 ; for ( int i = 1 ; i < m ; ++ i ) { ans += 9 * A ( 9 , i - 1 ); } boolean [] vis = new boolean [ 10 ]; for ( int i = m - 1 ; i >= 0 ; -- i ) { int v = digits . get ( i ); for ( int j = i == m - 1 ? 1 : 0 ; j < v ; ++ j ) { if ( vis [ j ]) { continue ; } ans += A ( 10 - ( m - i ), i ); } if ( vis [ v ]) { break ; } vis [ v ] = true ; if ( i == 0 ) { ++ ans ; } } return ans ; } private int A ( int m , int n ) { return n == 0 ? 1 : A ( m , n - 1 ) * ( m - n + 1 ); } }Video Solution
Watch the video walkthrough for Count Special Integers
Similar Questions
5 related questions you might find useful
Patterns:
Subscribe to Scale Engineer newsletter
Learn about System Design, Software Engineering, and interview experiences every week.
No spam, unsubscribe at any time.