comments | difficulty | edit_url | rating | source | tags | ||
---|---|---|---|---|---|---|---|
true |
Hard |
2230 |
Weekly Contest 128 Q4 |
|
Given an integer n
, return the number of positive integers in the range [1, n]
that have at least one repeated digit.
Example 1:
Input: n = 20 Output: 1 Explanation: The only positive number (<= 20) with at least 1 repeated digit is 11.
Example 2:
Input: n = 100 Output: 10 Explanation: The positive numbers (<= 100) with atleast 1 repeated digit are 11, 22, 33, 44, 55, 66, 77, 88, 99, and 100.
Example 3:
Input: n = 1000 Output: 262
Constraints:
1 <= n <= 109
The problem requires counting the number of integers in the range
Additionally, we can use a binary number to record the digits that have appeared in the number. For example, if the digits
Next, 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
- The integer
$i$ represents the current digit index, starting from$0$ . - The integer
$\textit{mask}$ represents the digits that have appeared so far, using a binary number. The$j$ -th bit of$\textit{mask}$ being$1$ indicates that digit$j$ has appeared, while$0$ indicates it has not. - The boolean
$\textit{lead}$ indicates whether the current number contains only leading zeros. - The boolean
$\textit{limit}$ indicates whether the current position is restricted by the upper bound.
The function executes as follows:
If
Otherwise, we calculate the upper bound
Then, we enumerate the current digit
The answer is
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
- 2376. Count Special Integers
class Solution:
def numDupDigitsAtMostN(self, n: int) -> int:
@cache
def dfs(i: int, mask: int, lead: bool, limit: bool) -> int:
if i >= len(s):
return lead ^ 1
up = int(s[i]) if limit else 9
ans = 0
for j in range(up + 1):
if lead and j == 0:
ans += dfs(i + 1, mask, True, False)
elif mask >> j & 1 ^ 1:
ans += dfs(i + 1, mask | 1 << j, False, limit and j == up)
return ans
s = str(n)
return n - dfs(0, 0, True, True)
class Solution {
private char[] s;
private Integer[][] f;
public int numDupDigitsAtMostN(int n) {
s = String.valueOf(n).toCharArray();
f = new Integer[s.length][1 << 10];
return n - 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 (!lead && !limit && 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 (lead && j == 0) {
ans += dfs(i + 1, mask, true, false);
} else if ((mask >> j & 1) == 0) {
ans += dfs(i + 1, mask | 1 << j, false, limit && j == up);
}
}
if (!lead && !limit) {
f[i][mask] = ans;
}
return ans;
}
}
class Solution {
public:
int numDupDigitsAtMostN(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 (!lead && !limit && 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 (lead && j == 0) {
ans += dfs(dfs, i + 1, mask, true, limit && j == up);
} else if (mask >> j & 1 ^ 1) {
ans += dfs(dfs, i + 1, mask | (1 << j), false, limit && j == up);
}
}
if (!lead && !limit) {
f[i][mask] = ans;
}
return ans;
};
return n - dfs(dfs, 0, 0, true, true);
}
};
func numDupDigitsAtMostN(n int) int {
s := []byte(strconv.Itoa(n))
m := len(s)
f := make([][]int, m)
for i := range f {
f[i] = make([]int, 1<<10)
for j := range f[i] {
f[i][j] = -1
}
}
var dfs func(i, mask int, lead, limit bool) int
dfs = func(i, mask int, lead, limit bool) int {
if i >= m {
if lead {
return 0
}
return 1
}
if !lead && !limit && 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 lead && j == 0 {
ans += dfs(i+1, mask, true, limit && j == up)
} else if mask>>j&1 == 0 {
ans += dfs(i+1, mask|(1<<j), false, limit && j == up)
}
}
if !lead && !limit {
f[i][mask] = ans
}
return ans
}
return n - dfs(0, 0, true, true)
}
function numDupDigitsAtMostN(n: number): number {
const s = n.toString();
const m = s.length;
const f = 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 (!lead && !limit && f[i][mask] !== -1) {
return f[i][mask];
}
const up = limit ? parseInt(s[i]) : 9;
let ans = 0;
for (let j = 0; j <= up; j++) {
if (lead && j === 0) {
ans += dfs(i + 1, mask, true, limit && j === up);
} else if (((mask >> j) & 1) === 0) {
ans += dfs(i + 1, mask | (1 << j), false, limit && j === up);
}
}
if (!lead && !limit) {
f[i][mask] = ans;
}
return ans;
};
return n - dfs(0, 0, true, true);
}