Skip to content

Commit af8bf48

Browse files
authored
feat: add solutions to lc problem: No.3032 (#2330)
No.3032.Count Numbers With Unique Digits II
1 parent 21058b4 commit af8bf48

File tree

7 files changed

+565
-2
lines changed

7 files changed

+565
-2
lines changed

solution/3000-3099/3032.Count Numbers With Unique Digits II/README.md

+194-1
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,217 @@ Given two <strong>positive</strong> integers <code>a</code> and <code>b</code>,
4242

4343
## 解法
4444

45-
### 方法一
45+
### 方法一:状态压缩 + 数位 DP
46+
47+
题目要求统计区间 $[a, b]$ 中的数中有多少个数的数位是唯一的,我们可以使用状态压缩和数位 DP 来解决这个问题。
48+
49+
我们可以用一个函数 $f(n)$ 来统计 $[1, n]$ 中的数中有多少个数的数位是唯一的,那么答案就是 $f(b) - f(a - 1)$。
50+
51+
另外,我们可以用一个二进制数来记录数字中出现过的数字,比如数字中出现了 $1, 3, 5$,那么我们可以用 $10101$ 来表示这个状态。
52+
53+
接下来,我们使用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。
54+
55+
基本步骤如下:
56+
57+
1. 我们将数字 $n$ 转换为字符串 $num$,其中 $num[0]$ 为最高位,而 $num[len - 1]$ 为最低位。
58+
2. 根据题目信息,设计一个函数 $dfs(pos, mask, limit)$,其中 $pos$ 表示当前处理的位置,$mask$ 表示当前数字中出现过的数字,$limit$ 表示当前位置是否有限制。如果 $limit$ 为真,那么当前位置的数字不能超过 $num[pos]$。
59+
60+
答案为 $dfs(0, 0, true)$。
61+
62+
时间复杂度 $O(m \times 2^{10} \times 10)$,空间复杂度 $O(m \times 2^{10})$。其中 $m$ 为 $b$ 的位数。
4663

4764
<!-- tabs:start -->
4865

4966
```python
67+
class Solution:
68+
def numberCount(self, a: int, b: int) -> int:
69+
@cache
70+
def dfs(pos: int, mask: int, limit: bool) -> int:
71+
if pos >= len(num):
72+
return 1 if mask else 0
73+
up = int(num[pos]) if limit else 9
74+
ans = 0
75+
for i in range(up + 1):
76+
if mask >> i & 1:
77+
continue
78+
nxt = 0 if mask == 0 and i == 0 else mask | 1 << i
79+
ans += dfs(pos + 1, nxt, limit and i == up)
80+
return ans
5081

82+
num = str(a - 1)
83+
x = dfs(0, 0, True)
84+
dfs.cache_clear()
85+
num = str(b)
86+
y = dfs(0, 0, True)
87+
return y - x
5188
```
5289

5390
```java
91+
class Solution {
92+
private String num;
93+
private Integer[][] f;
94+
95+
public int numberCount(int a, int b) {
96+
num = String.valueOf(a - 1);
97+
f = new Integer[num.length()][1 << 10];
98+
int x = dfs(0, 0, true);
99+
num = String.valueOf(b);
100+
f = new Integer[num.length()][1 << 10];
101+
int y = dfs(0, 0, true);
102+
return y - x;
103+
}
54104

105+
private int dfs(int pos, int mask, boolean limit) {
106+
if (pos >= num.length()) {
107+
return mask > 0 ? 1 : 0;
108+
}
109+
if (!limit && f[pos][mask] != null) {
110+
return f[pos][mask];
111+
}
112+
int up = limit ? num.charAt(pos) - '0' : 9;
113+
int ans = 0;
114+
for (int i = 0; i <= up; ++i) {
115+
if ((mask >> i & 1) == 1) {
116+
continue;
117+
}
118+
int nxt = mask == 0 && i == 0 ? 0 : mask | 1 << i;
119+
ans += dfs(pos + 1, nxt, limit && i == up);
120+
}
121+
if (!limit) {
122+
f[pos][mask] = ans;
123+
}
124+
return ans;
125+
}
126+
}
55127
```
56128

57129
```cpp
130+
class Solution {
131+
public:
132+
int numberCount(int a, int b) {
133+
string num = to_string(b);
134+
int f[num.size()][1 << 10];
135+
memset(f, -1, sizeof(f));
136+
function<int(int, int, bool)> dfs = [&](int pos, int mask, bool limit) {
137+
if (pos >= num.size()) {
138+
return mask ? 1 : 0;
139+
}
140+
if (!limit && f[pos][mask] != -1) {
141+
return f[pos][mask];
142+
}
143+
int up = limit ? num[pos] - '0' : 9;
144+
int ans = 0;
145+
for (int i = 0; i <= up; ++i) {
146+
if (mask >> i & 1) {
147+
continue;
148+
}
149+
int nxt = mask == 0 && i == 0 ? 0 : mask | 1 << i;
150+
ans += dfs(pos + 1, nxt, limit && i == up);
151+
}
152+
if (!limit) {
153+
f[pos][mask] = ans;
154+
}
155+
return ans;
156+
};
58157

158+
int y = dfs(0, 0, true);
159+
num = to_string(a - 1);
160+
memset(f, -1, sizeof(f));
161+
int x = dfs(0, 0, true);
162+
return y - x;
163+
}
164+
};
59165
```
60166

61167
```go
168+
func numberCount(a int, b int) int {
169+
num := strconv.Itoa(b)
170+
f := make([][1 << 10]int, len(num))
171+
for i := range f {
172+
for j := range f[i] {
173+
f[i][j] = -1
174+
}
175+
}
176+
var dfs func(pos, mask int, limit bool) int
177+
dfs = func(pos, mask int, limit bool) int {
178+
if pos >= len(num) {
179+
if mask != 0 {
180+
return 1
181+
}
182+
return 0
183+
}
184+
if !limit && f[pos][mask] != -1 {
185+
return f[pos][mask]
186+
}
187+
up := 9
188+
if limit {
189+
up = int(num[pos] - '0')
190+
}
191+
ans := 0
192+
for i := 0; i <= up; i++ {
193+
if mask>>i&1 == 1 {
194+
continue
195+
}
196+
nxt := mask | 1<<i
197+
if mask == 0 && i == 0 {
198+
nxt = 0
199+
}
200+
ans += dfs(pos+1, nxt, limit && i == up)
201+
}
202+
if !limit {
203+
f[pos][mask] = ans
204+
}
205+
return ans
206+
}
207+
y := dfs(0, 0, true)
208+
num = strconv.Itoa(a - 1)
209+
for i := range f {
210+
for j := range f[i] {
211+
f[i][j] = -1
212+
}
213+
}
214+
x := dfs(0, 0, true)
215+
return y - x
216+
}
217+
```
218+
219+
```ts
220+
function numberCount(a: number, b: number): number {
221+
let num: string = b.toString();
222+
const f: number[][] = Array(num.length)
223+
.fill(0)
224+
.map(() => Array(1 << 10).fill(-1));
225+
const dfs: (pos: number, mask: number, limit: boolean) => number = (pos, mask, limit) => {
226+
if (pos >= num.length) {
227+
return mask ? 1 : 0;
228+
}
229+
if (!limit && f[pos][mask] !== -1) {
230+
return f[pos][mask];
231+
}
232+
const up: number = limit ? +num[pos] : 9;
233+
let ans: number = 0;
234+
for (let i = 0; i <= up; i++) {
235+
if ((mask >> i) & 1) {
236+
continue;
237+
}
238+
let nxt: number = mask | (1 << i);
239+
if (mask === 0 && i === 0) {
240+
nxt = 0;
241+
}
242+
ans += dfs(pos + 1, nxt, limit && i === up);
243+
}
244+
if (!limit) {
245+
f[pos][mask] = ans;
246+
}
247+
return ans;
248+
};
62249

250+
const y: number = dfs(0, 0, true);
251+
num = (a - 1).toString();
252+
f.forEach(v => v.fill(-1));
253+
const x: number = dfs(0, 0, true);
254+
return y - x;
255+
}
63256
```
64257

65258
<!-- tabs:end -->

0 commit comments

Comments
 (0)