Skip to content

Commit e49af42

Browse files
committed
feat: add solutions to lc problem: No.0357
No.0357.Count Numbers with Unique Digits
1 parent 9d6c7e5 commit e49af42

File tree

11 files changed

+353
-73
lines changed

11 files changed

+353
-73
lines changed

solution/0300-0399/0357.Count Numbers with Unique Digits/README.md

+169
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,46 @@
4141

4242
<!-- 这里可写通用的实现逻辑 -->
4343

44+
**方法一:排列组合**
45+
46+
当 $n=0$ 时,有 $0\le x \lt 1$,只有 $1$ 个数字,即 $0$。
47+
48+
当 $n=1$ 时,有 $0\le x \lt 10$,有 $10$ 个数字,即 $0,1,2,3,4,5,6,7,8,9$。
49+
50+
当 $n=2$ 时,有 $0\le x \lt 100$,那么 $x$ 的选择可以由两部分组成:只有一位数的数字和有两位数的数字。对于只有一位数的情况,可以由上述的边界情况计算;对于有两位数的情况,由于第一位数字不能为 $0$,所以第一位数字有 $9$ 种选择,第二位数字有 $9$ 种选择,所以有 $9 \times 9$ 种选择,即 $81$ 种选择。
51+
52+
更一般的情况,含有 $n$ 位数且各位数字都不同的数字 $x$ 的个数为 $9 \times A_{9}^{n-1}$。再加上含有小于 $n$ 位数且各位数字都不同的数字 $x$ 的个数,即为答案。
53+
54+
时间复杂度 $O(n)$。
55+
56+
**方法二:状态压缩 + 数位 DP**
57+
58+
这道题实际上是求在给定区间 $[l,..r]$ 中,满足条件的数的个数。条件与数的大小无关,而只与数的组成有关,因此可以使用数位 DP 的思想求解。数位 DP 中,数的大小对复杂度的影响很小。
59+
60+
对于区间 $[l,..r]$ 问题,我们一般会将其转化为 $[1,..r]$ 然后再减去 $[1,..l - 1]$ 的问题,即:
61+
62+
$$
63+
ans = \sum_{i=1}^{r} ans_i - \sum_{i=1}^{l-1} ans_i
64+
$$
65+
66+
不过对于本题而言,我们只需要求出区间 $[1,..10^n-1]$ 的值即可。
67+
68+
这里我们用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。
69+
70+
我们根据题目信息,设计函数 $dfs()$,对于本题,我们定义 $dfs(pos, mask, lead)$,答案为 $dfs(len, 0, true)$。
71+
72+
其中:
73+
74+
- `pos` 表示数字的位数,从末位或者第一位开始,一般根据题目的数字构造性质来选择顺序。对于本题,我们选择从高位开始,因此,`pos` 的初始值为 `len`
75+
- `mask` 表示当前数字选取了哪些数字(状态压缩);
76+
- `lead` 表示当前数字是否含有前导零;
77+
78+
关于函数的实现细节,可以参考下面的代码。
79+
80+
时间复杂度 $O(n)$。
81+
82+
相似题目:[233. 数字 1 的个数](/solution/0200-0299/0233.Number%20of%20Digit%20One/README.md)
83+
4484
<!-- tabs:start -->
4585

4686
### **Python3**
@@ -61,6 +101,26 @@ class Solution:
61101
return ans
62102
```
63103

104+
```python
105+
class Solution:
106+
def countNumbersWithUniqueDigits(self, n: int) -> int:
107+
@cache
108+
def dfs(pos, mask, lead):
109+
if pos <= 0:
110+
return 1
111+
ans = 0
112+
for i in range(10):
113+
if (mask >> i) & 1:
114+
continue
115+
if i == 0 and lead:
116+
ans += dfs(pos - 1, mask, lead)
117+
else:
118+
ans += dfs(pos - 1, mask | (1 << i), False)
119+
return ans
120+
121+
return dfs(n, 0, True)
122+
```
123+
64124
### **Java**
65125

66126
<!-- 这里可写当前语言的特殊实现逻辑 -->
@@ -84,6 +144,43 @@ class Solution {
84144
}
85145
```
86146

147+
```java
148+
class Solution {
149+
private int[][] dp = new int[10][1 << 11];
150+
151+
public int countNumbersWithUniqueDigits(int n) {
152+
for (var e : dp) {
153+
Arrays.fill(e, -1);
154+
}
155+
return dfs(n, 0, true);
156+
}
157+
158+
private int dfs(int pos, int mask, boolean lead) {
159+
if (pos <= 0) {
160+
return 1;
161+
}
162+
if (!lead && dp[pos][mask] != -1) {
163+
return dp[pos][mask];
164+
}
165+
int ans = 0;
166+
for (int i = 0; i < 10; ++i) {
167+
if (((mask >> i) & 1) == 1) {
168+
continue;
169+
}
170+
if (i == 0 && lead) {
171+
ans += dfs(pos - 1, mask, lead);
172+
} else {
173+
ans += dfs(pos - 1, mask | (1 << i), false);
174+
}
175+
}
176+
if (!lead) {
177+
dp[pos][mask] = ans;
178+
}
179+
return ans;
180+
}
181+
}
182+
```
183+
87184
### **C++**
88185

89186
```cpp
@@ -102,6 +199,40 @@ public:
102199
};
103200
```
104201
202+
```cpp
203+
class Solution {
204+
public:
205+
int dp[10][1 << 11];
206+
207+
int countNumbersWithUniqueDigits(int n) {
208+
memset(dp, -1, sizeof dp);
209+
return dfs(n, 0, true);
210+
}
211+
212+
int dfs(int pos, int mask, bool lead) {
213+
if (pos <= 0) {
214+
return 1;
215+
}
216+
if (!lead && dp[pos][mask] != -1) {
217+
return dp[pos][mask];
218+
}
219+
int ans = 0;
220+
for (int i = 0; i < 10; ++i) {
221+
if ((mask >> i) & 1) continue;
222+
if (i == 0 && lead) {
223+
ans += dfs(pos - 1, mask, lead);
224+
} else {
225+
ans += dfs(pos - 1, mask | 1 << i, false);
226+
}
227+
}
228+
if (!lead) {
229+
dp[pos][mask] = ans;
230+
}
231+
return ans;
232+
}
233+
};
234+
```
235+
105236
### **Go**
106237

107238
```go
@@ -121,6 +252,44 @@ func countNumbersWithUniqueDigits(n int) int {
121252
}
122253
```
123254

255+
```go
256+
func countNumbersWithUniqueDigits(n int) int {
257+
dp := make([][]int, 10)
258+
for i := range dp {
259+
dp[i] = make([]int, 1<<11)
260+
for j := range dp[i] {
261+
dp[i][j] = -1
262+
}
263+
}
264+
var dfs func(int, int, bool) int
265+
dfs = func(pos, mask int, lead bool) int {
266+
if pos <= 0 {
267+
return 1
268+
}
269+
if !lead && dp[pos][mask] != -1 {
270+
return dp[pos][mask]
271+
}
272+
ans := 0
273+
for i := 0; i < 10; i++ {
274+
if ((mask >> i) & 1) == 1 {
275+
continue
276+
}
277+
if i == 0 && lead {
278+
ans += dfs(pos-1, mask, lead)
279+
} else {
280+
ans += dfs(pos-1, mask|1<<i, false)
281+
}
282+
}
283+
if !lead {
284+
dp[pos][mask] = ans
285+
}
286+
return ans
287+
}
288+
289+
return dfs(n, 0, true)
290+
}
291+
```
292+
124293
### **...**
125294

126295
```

solution/0300-0399/0357.Count Numbers with Unique Digits/README_EN.md

+129
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,26 @@ class Solution:
4949
return ans
5050
```
5151

52+
```python
53+
class Solution:
54+
def countNumbersWithUniqueDigits(self, n: int) -> int:
55+
@cache
56+
def dfs(pos, mask, lead):
57+
if pos <= 0:
58+
return 1
59+
ans = 0
60+
for i in range(10):
61+
if (mask >> i) & 1:
62+
continue
63+
if i == 0 and lead:
64+
ans += dfs(pos - 1, mask, lead)
65+
else:
66+
ans += dfs(pos - 1, mask | (1 << i), False)
67+
return ans
68+
69+
return dfs(n, 0, True)
70+
```
71+
5272
### **Java**
5373

5474
```java
@@ -70,6 +90,43 @@ class Solution {
7090
}
7191
```
7292

93+
```java
94+
class Solution {
95+
private int[][] dp = new int[10][1 << 11];
96+
97+
public int countNumbersWithUniqueDigits(int n) {
98+
for (var e : dp) {
99+
Arrays.fill(e, -1);
100+
}
101+
return dfs(n, 0, true);
102+
}
103+
104+
private int dfs(int pos, int mask, boolean lead) {
105+
if (pos <= 0) {
106+
return 1;
107+
}
108+
if (!lead && dp[pos][mask] != -1) {
109+
return dp[pos][mask];
110+
}
111+
int ans = 0;
112+
for (int i = 0; i < 10; ++i) {
113+
if (((mask >> i) & 1) == 1) {
114+
continue;
115+
}
116+
if (i == 0 && lead) {
117+
ans += dfs(pos - 1, mask, lead);
118+
} else {
119+
ans += dfs(pos - 1, mask | (1 << i), false);
120+
}
121+
}
122+
if (!lead) {
123+
dp[pos][mask] = ans;
124+
}
125+
return ans;
126+
}
127+
}
128+
```
129+
73130
### **C++**
74131

75132
```cpp
@@ -88,6 +145,40 @@ public:
88145
};
89146
```
90147
148+
```cpp
149+
class Solution {
150+
public:
151+
int dp[10][1 << 11];
152+
153+
int countNumbersWithUniqueDigits(int n) {
154+
memset(dp, -1, sizeof dp);
155+
return dfs(n, 0, true);
156+
}
157+
158+
int dfs(int pos, int mask, bool lead) {
159+
if (pos <= 0) {
160+
return 1;
161+
}
162+
if (!lead && dp[pos][mask] != -1) {
163+
return dp[pos][mask];
164+
}
165+
int ans = 0;
166+
for (int i = 0; i < 10; ++i) {
167+
if ((mask >> i) & 1) continue;
168+
if (i == 0 && lead) {
169+
ans += dfs(pos - 1, mask, lead);
170+
} else {
171+
ans += dfs(pos - 1, mask | 1 << i, false);
172+
}
173+
}
174+
if (!lead) {
175+
dp[pos][mask] = ans;
176+
}
177+
return ans;
178+
}
179+
};
180+
```
181+
91182
### **Go**
92183

93184
```go
@@ -107,6 +198,44 @@ func countNumbersWithUniqueDigits(n int) int {
107198
}
108199
```
109200

201+
```go
202+
func countNumbersWithUniqueDigits(n int) int {
203+
dp := make([][]int, 10)
204+
for i := range dp {
205+
dp[i] = make([]int, 1<<11)
206+
for j := range dp[i] {
207+
dp[i][j] = -1
208+
}
209+
}
210+
var dfs func(int, int, bool) int
211+
dfs = func(pos, mask int, lead bool) int {
212+
if pos <= 0 {
213+
return 1
214+
}
215+
if !lead && dp[pos][mask] != -1 {
216+
return dp[pos][mask]
217+
}
218+
ans := 0
219+
for i := 0; i < 10; i++ {
220+
if ((mask >> i) & 1) == 1 {
221+
continue
222+
}
223+
if i == 0 && lead {
224+
ans += dfs(pos-1, mask, lead)
225+
} else {
226+
ans += dfs(pos-1, mask|1<<i, false)
227+
}
228+
}
229+
if !lead {
230+
dp[pos][mask] = ans
231+
}
232+
return ans
233+
}
234+
235+
return dfs(n, 0, true)
236+
}
237+
```
238+
110239
### **...**
111240

112241
```

0 commit comments

Comments
 (0)