29
29
<pre >
30
30
<strong >输入:</strong >n = 2
31
31
<strong >输出:</strong >91
32
- <strong >解释:</strong >答案应为除去 <code >11、22、33、44、55、66、77、88、99 </code >外,在 0 ≤ x < ; 100 范围内的所有数字。
32
+ <strong >解释:</strong >答案应为除去 <code >11、22、33、44、55、66、77、88、99 </code >外,在 0 ≤ x < ; 100 范围内的所有数字。
33
33
</pre >
34
34
35
35
<p ><strong >示例 2:</strong ></p >
@@ -55,101 +55,7 @@ tags:
55
55
56
56
<!-- solution:start -->
57
57
58
- ### 方法一:排列组合
59
-
60
- 当 $n=0$ 时,有 $0\le x \lt 1$,只有 $1$ 个数字,即 $0$。
61
-
62
- 当 $n=1$ 时,有 $0\le x \lt 10$,有 $10$ 个数字,即 $0,1,2,3,4,5,6,7,8,9$。
63
-
64
- 当 $n=2$ 时,有 $0\le x \lt 100$,那么 $x$ 的选择可以由两部分组成:只有一位数的数字和有两位数的数字。对于只有一位数的情况,可以由上述的边界情况计算;对于有两位数的情况,由于第一位数字不能为 $0$,所以第一位数字有 $9$ 种选择,第二位数字有 $9$ 种选择,所以有 $9 \times 9$ 种选择,即 $81$ 种选择。
65
-
66
- 更一般的情况,含有 $n$ 位数且各位数字都不同的数字 $x$ 的个数为 $9 \times A_ {9}^{n-1}$。再加上含有小于 $n$ 位数且各位数字都不同的数字 $x$ 的个数,即为答案。
67
-
68
- 时间复杂度 $O(n)$。
69
-
70
- <!-- tabs:start -->
71
-
72
- #### Python3
73
-
74
- ``` python
75
- class Solution :
76
- def countNumbersWithUniqueDigits (self , n : int ) -> int :
77
- if n == 0 :
78
- return 1
79
- if n == 1 :
80
- return 10
81
- ans, cur = 10 , 9
82
- for i in range (n - 1 ):
83
- cur *= 9 - i
84
- ans += cur
85
- return ans
86
- ```
87
-
88
- #### Java
89
-
90
- ``` java
91
- class Solution {
92
- public int countNumbersWithUniqueDigits (int n ) {
93
- if (n == 0 ) {
94
- return 1 ;
95
- }
96
- if (n == 1 ) {
97
- return 10 ;
98
- }
99
- int ans = 10 ;
100
- for (int i = 0 , cur = 9 ; i < n - 1 ; ++ i) {
101
- cur *= (9 - i);
102
- ans += cur;
103
- }
104
- return ans;
105
- }
106
- }
107
- ```
108
-
109
- #### C++
110
-
111
- ``` cpp
112
- class Solution {
113
- public:
114
- int countNumbersWithUniqueDigits(int n) {
115
- if (n == 0) return 1;
116
- if (n == 1) return 10;
117
- int ans = 10;
118
- for (int i = 0, cur = 9; i < n - 1; ++i) {
119
- cur * = (9 - i);
120
- ans += cur;
121
- }
122
- return ans;
123
- }
124
- };
125
- ```
126
-
127
- #### Go
128
-
129
- ```go
130
- func countNumbersWithUniqueDigits(n int) int {
131
- if n == 0 {
132
- return 1
133
- }
134
- if n == 1 {
135
- return 10
136
- }
137
- ans := 10
138
- for i, cur := 0, 9; i < n-1; i++ {
139
- cur *= (9 - i)
140
- ans += cur
141
- }
142
- return ans
143
- }
144
- ```
145
-
146
- <!-- tabs: end -->
147
-
148
- <!-- solution: end -->
149
-
150
- <!-- solution: start -->
151
-
152
- ### 方法二:状态压缩 + 数位 DP
58
+ ### 方法一:状态压缩 + 数位 DP
153
59
154
60
这道题实际上是求在给定区间 $[ l,..r] $ 中,满足条件的数的个数。条件与数的大小无关,而只与数的组成有关,因此可以使用数位 DP 的思想求解。数位 DP 中,数的大小对复杂度的影响很小。
155
61
163
69
164
70
这里我们用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。
165
71
166
- 我们根据题目信息,设计函数 $dfs()$,对于本题,我们定义 $dfs(pos, mask, lead)$,答案为 $dfs(len, 0, true)$。
72
+ 我们根据题目信息,设计一个函数 $\textit{dfs}(i, \textit{mask}, \textit{lead})$,其中:
73
+
74
+ - 数字 $i$ 表示当前搜索到的位置,我们从高位开始搜索,即 $i = 0$ 表示最高位。
75
+ - 数字 $\textit{mask}$ 表示当前数字的状态,即 $\textit{mask}$ 的第 $j$ 位为 $1$ 表示数字 $j$ 已经被使用过。
76
+ - 布尔值 $\textit{lead}$ 表示当前是否只包含前导 $0$。
167
77
168
- 其中 :
78
+ 函数的执行过程如下 :
169
79
170
- - ` pos ` 表示数字的位数,从末位或者第一位开始,一般根据题目的数字构造性质来选择顺序。对于本题,我们选择从高位开始,因此,` pos ` 的初始值为 ` len ` ;
171
- - ` mask ` 表示当前数字选取了哪些数字(状态压缩);
172
- - ` lead ` 表示当前数字是否含有前导零;
80
+ 如果 $i$ 超过了数字 $n$ 的长度,即 $i \lt 0$,说明搜索结束,直接返回 $1$。
81
+
82
+ 否则,我们从 $0$ 到 $9$ 枚举位置 $i$ 的数字 $j$,对于每一个 $j$:
83
+
84
+ - 如果 $\textit{mask}$ 的第 $j$ 位为 $1$,说明数字 $j$ 已经被使用过,直接跳过。
85
+ - 如果 $\textit{lead}$ 为真且 $j = 0$,说明当前数字只包含前导 $0$,递归到下一层时,此时 $\textit{lead}$ 仍为真。
86
+ - 否则,我们递归到下一层,更新 $\textit{mask}$ 的第 $j$ 位为 $1$,并将 $\textit{lead}$ 更新为假。
87
+
88
+ 最后,我们将所有递归到下一层的结果累加,即为答案。
89
+
90
+ 答案为 $\textit{dfs}(n - 1, 0, \textit{True})$。
173
91
174
92
关于函数的实现细节,可以参考下面的代码。
175
93
176
- 时间复杂度 $O(n) $。
94
+ 时间复杂度 $O(n \times 2^D \times D)$,空间复杂度 $O(n \times 2^D)$。其中 $n$ 为数字 $n$ 的长度,而 $D = 10 $。
177
95
178
96
相似题目:
179
97
192
110
class Solution :
193
111
def countNumbersWithUniqueDigits (self , n : int ) -> int :
194
112
@cache
195
- def dfs (pos , mask , lead ) :
196
- if pos <= 0 :
113
+ def dfs (i : int , mask : int , lead : bool ) -> int :
114
+ if i < 0 :
197
115
return 1
198
116
ans = 0
199
- for i in range (10 ):
200
- if ( mask >> i) & 1 :
117
+ for j in range (10 ):
118
+ if mask >> j & 1 :
201
119
continue
202
- if i == 0 and lead :
203
- ans += dfs(pos - 1 , mask, lead )
120
+ if lead and j == 0 :
121
+ ans += dfs(i - 1 , mask, True )
204
122
else :
205
- ans += dfs(pos - 1 , mask | ( 1 << i) , False )
123
+ ans += dfs(i - 1 , mask | 1 << j , False )
206
124
return ans
207
125
208
- return dfs(n, 0 , True )
126
+ return dfs(n - 1 , 0 , True )
209
127
```
210
128
211
129
#### Java
212
130
213
131
``` java
214
132
class Solution {
215
- private int [][] dp = new int [ 10 ][ 1 << 11 ] ;
133
+ private Integer [][] f ;
216
134
217
135
public int countNumbersWithUniqueDigits (int n ) {
218
- for (var e : dp) {
219
- Arrays . fill(e, - 1 );
220
- }
221
- return dfs(n, 0 , true );
136
+ f = new Integer [n][1 << 10 ];
137
+ return dfs(n - 1 , 0 , true );
222
138
}
223
139
224
- private int dfs (int pos , int mask , boolean lead ) {
225
- if (pos <= 0 ) {
140
+ private int dfs (int i , int mask , boolean lead ) {
141
+ if (i < 0 ) {
226
142
return 1 ;
227
143
}
228
- if (! lead && dp[pos ][mask] != - 1 ) {
229
- return dp[pos ][mask];
144
+ if (! lead && f[i ][mask] != null ) {
145
+ return f[i ][mask];
230
146
}
231
147
int ans = 0 ;
232
- for (int i = 0 ; i < 10 ; ++ i ) {
233
- if ((( mask >> i) & 1 ) == 1 ) {
148
+ for (int j = 0 ; j <= 9 ; ++ j ) {
149
+ if ((mask >> j & 1 ) == 1 ) {
234
150
continue ;
235
151
}
236
- if (i == 0 && lead ) {
237
- ans += dfs(pos - 1 , mask, lead );
152
+ if (lead && j == 0 ) {
153
+ ans += dfs(i - 1 , mask, true );
238
154
} else {
239
- ans += dfs(pos - 1 , mask | ( 1 << i) , false );
155
+ ans += dfs(i - 1 , mask | 1 << j , false );
240
156
}
241
157
}
242
158
if (! lead) {
243
- dp[pos ][mask] = ans;
159
+ f[i ][mask] = ans;
244
160
}
245
161
return ans;
246
162
}
@@ -252,33 +168,33 @@ class Solution {
252
168
``` cpp
253
169
class Solution {
254
170
public:
255
- int dp[ 10] [ 1 << 11 ] ;
256
-
257
171
int countNumbersWithUniqueDigits(int n) {
258
- memset(dp, -1, sizeof dp);
259
- return dfs(n, 0, true);
260
- }
261
-
262
- int dfs (int pos, int mask, bool lead) {
263
- if (pos <= 0) {
264
- return 1;
265
- }
266
- if (!lead && dp[ pos] [ mask ] != -1) {
267
- return dp[ pos] [ mask ] ;
268
- }
269
- int ans = 0;
270
- for (int i = 0; i < 10; ++i) {
271
- if ((mask >> i) & 1) continue;
272
- if (i == 0 && lead) {
273
- ans += dfs(pos - 1, mask, lead);
274
- } else {
275
- ans += dfs(pos - 1, mask | 1 << i, false);
172
+ int f[ n + 1] [ 1 << 10 ] ;
173
+ memset(f, -1, sizeof(f));
174
+ auto dfs = [ &] (auto&& dfs, int i, int mask, bool lead) -> int {
175
+ if (i < 0) {
176
+ return 1;
276
177
}
277
- }
278
- if (!lead) {
279
- dp[ pos] [ mask ] = ans;
280
- }
281
- return ans;
178
+ if (!lead && f[ i] [ mask ] != -1) {
179
+ return f[ i] [ mask ] ;
180
+ }
181
+ int ans = 0;
182
+ for (int j = 0; j <= 9; ++j) {
183
+ if (mask >> j & 1) {
184
+ continue;
185
+ }
186
+ if (lead && j == 0) {
187
+ ans += dfs(dfs, i - 1, mask, true);
188
+ } else {
189
+ ans += dfs(dfs, i - 1, mask | 1 << i, false);
190
+ }
191
+ }
192
+ if (!lead) {
193
+ f[ i] [ mask ] = ans;
194
+ }
195
+ return ans;
196
+ };
197
+ return dfs(dfs, n - 1, 0, true);
282
198
}
283
199
};
284
200
```
@@ -287,39 +203,69 @@ public:
287
203
288
204
```go
289
205
func countNumbersWithUniqueDigits(n int) int {
290
- dp := make([][]int, 10)
291
- for i := range dp {
292
- dp[i] = make([]int, 1<<11)
293
- for j := range dp[i] {
294
- dp[i][j] = -1
206
+ f := make([][1 << 10]int, n)
207
+ for i := range f {
208
+ for j := range f[i] {
209
+ f[i][j] = -1
295
210
}
296
211
}
297
- var dfs func(int, int, bool) int
298
- dfs = func(pos , mask int, lead bool) int {
299
- if pos <= 0 {
212
+ var dfs func(i, mask int, lead bool) int
213
+ dfs = func(i , mask int, lead bool) int {
214
+ if i < 0 {
300
215
return 1
301
216
}
302
- if !lead && dp[pos ][mask] != -1 {
303
- return dp[pos ][mask]
217
+ if !lead && f[i ][mask] != -1 {
218
+ return f[i ][mask]
304
219
}
305
220
ans := 0
306
- for i := 0; i < 10; i ++ {
307
- if (( mask >> i) & 1) == 1 {
221
+ for j := 0; j < 10; j ++ {
222
+ if mask>>j&1 == 1 {
308
223
continue
309
224
}
310
- if i == 0 && lead {
311
- ans += dfs(pos -1, mask, lead )
225
+ if lead && j == 0 {
226
+ ans += dfs(i -1, mask, true )
312
227
} else {
313
- ans += dfs(pos -1, mask|1<<i , false)
228
+ ans += dfs(i -1, mask|1<<j , false)
314
229
}
315
230
}
316
231
if !lead {
317
- dp[pos ][mask] = ans
232
+ f[i ][mask] = ans
318
233
}
319
234
return ans
320
235
}
236
+ return dfs(n-1, 0, true)
237
+ }
238
+ ```
239
+
240
+ #### TypeScript
321
241
322
- return dfs(n, 0, true)
242
+ ``` ts
243
+ function countNumbersWithUniqueDigits(n : number ): number {
244
+ const f: number [][] = Array .from ({ length: n }, () => Array (1 << 10 ).fill (- 1 ));
245
+ const dfs = (i : number , mask : number , lead : boolean ): number => {
246
+ if (i < 0 ) {
247
+ return 1 ;
248
+ }
249
+ if (! lead && f [i ][mask ] !== - 1 ) {
250
+ return f [i ][mask ];
251
+ }
252
+ let ans = 0 ;
253
+ for (let j = 0 ; j < 10 ; ++ j ) {
254
+ if ((mask >> j ) & 1 ) {
255
+ continue ;
256
+ }
257
+ if (lead && j === 0 ) {
258
+ ans += dfs (i - 1 , mask , true );
259
+ } else {
260
+ ans += dfs (i - 1 , mask | (1 << j ), false );
261
+ }
262
+ }
263
+ if (! lead ) {
264
+ f [i ][mask ] = ans ;
265
+ }
266
+ return ans ;
267
+ };
268
+ return dfs (n - 1 , 0 , true );
323
269
}
324
270
```
325
271
0 commit comments