@@ -42,24 +42,217 @@ Given two <strong>positive</strong> integers <code>a</code> and <code>b</code>,
42
42
43
43
## 解法
44
44
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$ 的位数。
46
63
47
64
<!-- tabs:start -->
48
65
49
66
``` 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
50
81
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
51
88
```
52
89
53
90
``` 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
+ }
54
104
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
+ }
55
127
```
56
128
57
129
``` 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
+ };
58
157
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
+ };
59
165
```
60
166
61
167
``` 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
+ };
62
249
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
+ }
63
256
```
64
257
65
258
<!-- tabs:end -->
0 commit comments