comments | difficulty | edit_url | rating | source | tags | ||
---|---|---|---|---|---|---|---|
true |
Hard |
2120 |
Weekly Contest 306 Q4 |
|
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
This problem essentially asks for the number of numbers in the given range
For the range
However, for this problem, we only need to find the value for the range
Here, we use memoized search to implement Digit DP. We search from the starting point downwards, and at the lowest level, we get the number of solutions. We then return the answers layer by layer upwards, and finally get the final answer from the starting point of the search.
Based on the problem information, we design a function
- The digit
$i$ represents the current position being searched, starting from the highest digit, i.e.,$i = 0$ represents the highest digit. - The digit
$\textit{mask}$ represents the current state of the number, i.e., the$j$ -th bit of$\textit{mask}$ being$1$ indicates that the digit$j$ has been used. - The boolean
$\textit{lead}$ indicates whether the current number only contains leading $0$s. - The boolean
$\textit{limit}$ indicates whether the current number is restricted by the upper bound.
The function executes as follows:
If
If
Otherwise, we calculate the current upper bound
Then we iterate over
Finally, if
Return the final answer.
The time complexity is
Similar Problems:
- 233. Number of Digit One
- 357. Count Numbers with Unique Digits
- 600. Non-negative Integers without Consecutive Ones
- 788. Rotated Digits
- 902. Numbers At Most N Given Digit Set
- 1012. Numbers with Repeated Digits
class Solution:
def countSpecialNumbers(self, n: int) -> int:
@cache
def dfs(i: int, mask: int, lead: bool, limit: bool) -> int:
if i >= len(s):
return int(lead ^ 1)
up = int(s[i]) if limit else 9
ans = 0
for j in range(up + 1):
if mask >> j & 1:
continue
if lead and j == 0:
ans += dfs(i + 1, mask, True, limit and j == up)
else:
ans += dfs(i + 1, mask | 1 << j, False, limit and j == up)
return ans
s = str(n)
return dfs(0, 0, True, True)
class Solution {
private char[] s;
private Integer[][] f;
public int countSpecialNumbers(int n) {
s = String.valueOf(n).toCharArray();
f = new Integer[s.length][1 << 10];
return dfs(0, 0, true, true);
}
private int dfs(int i, int mask, boolean lead, boolean limit) {
if (i >= s.length) {
return lead ? 0 : 1;
}
if (!limit && !lead && f[i][mask] != null) {
return f[i][mask];
}
int up = limit ? s[i] - '0' : 9;
int ans = 0;
for (int j = 0; j <= up; ++j) {
if ((mask >> j & 1) == 1) {
continue;
}
if (lead && j == 0) {
ans += dfs(i + 1, mask, true, limit && j == up);
} else {
ans += dfs(i + 1, mask | (1 << j), false, limit && j == up);
}
}
if (!limit && !lead) {
f[i][mask] = ans;
}
return ans;
}
}
class Solution {
public:
int countSpecialNumbers(int n) {
string s = to_string(n);
int m = s.size();
int f[m][1 << 10];
memset(f, -1, sizeof(f));
auto dfs = [&](auto&& dfs, int i, int mask, bool lead, bool limit) -> int {
if (i >= m) {
return lead ^ 1;
}
if (!limit && !lead && f[i][mask] != -1) {
return f[i][mask];
}
int up = limit ? s[i] - '0' : 9;
int ans = 0;
for (int j = 0; j <= up; ++j) {
if (mask >> j & 1) {
continue;
}
if (lead && j == 0) {
ans += dfs(dfs, i + 1, mask, true, limit && j == up);
} else {
ans += dfs(dfs, i + 1, mask | (1 << j), false, limit && j == up);
}
}
if (!limit && !lead) {
f[i][mask] = ans;
}
return ans;
};
return dfs(dfs, 0, 0, true, true);
}
};
func countSpecialNumbers(n int) int {
s := strconv.Itoa(n)
m := len(s)
f := make([][1 << 10]int, m+1)
for i := range f {
for j := range f[i] {
f[i][j] = -1
}
}
var dfs func(int, int, bool, bool) int
dfs = func(i, mask int, lead, limit bool) int {
if i >= m {
if lead {
return 0
}
return 1
}
if !limit && !lead && f[i][mask] != -1 {
return f[i][mask]
}
up := 9
if limit {
up = int(s[i] - '0')
}
ans := 0
for j := 0; j <= up; j++ {
if mask>>j&1 == 1 {
continue
}
if lead && j == 0 {
ans += dfs(i+1, mask, true, limit && j == up)
} else {
ans += dfs(i+1, mask|1<<j, false, limit && j == up)
}
}
if !limit && !lead {
f[i][mask] = ans
}
return ans
}
return dfs(0, 0, true, true)
}
function countSpecialNumbers(n: number): number {
const s = n.toString();
const m = s.length;
const f: number[][] = Array.from({ length: m }, () => Array(1 << 10).fill(-1));
const dfs = (i: number, mask: number, lead: boolean, limit: boolean): number => {
if (i >= m) {
return lead ? 0 : 1;
}
if (!limit && !lead && f[i][mask] !== -1) {
return f[i][mask];
}
const up = limit ? +s[i] : 9;
let ans = 0;
for (let j = 0; j <= up; ++j) {
if ((mask >> j) & 1) {
continue;
}
if (lead && j === 0) {
ans += dfs(i + 1, mask, true, limit && j === up);
} else {
ans += dfs(i + 1, mask | (1 << j), false, limit && j === up);
}
}
if (!limit && !lead) {
f[i][mask] = ans;
}
return ans;
};
return dfs(0, 0, true, true);
}