Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit af8bf48

Browse files
feat: add solutions to lc problem: No.3032 (doocs#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‎

Lines changed: 194 additions & 1 deletion
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)

AltStyle によって変換されたページ (->オリジナル) /