47
47
48
48
时间复杂度 $O(n\times \log n)$。
49
49
50
+ ** 方法二:数位 DP**
51
+
52
+ 方法一的做法足以通过本题,但时间复杂度较高。如果题目的数据范围达到 $10^9$ 级别,则方法一的做法会超出时间限制。
53
+
54
+ 这道题实际上是求在给定区间 $[ l, r] $ 中,满足条件的数的个数。条件与数的大小无关,而只与数的组成有关,因此可以使用数位 DP 的思想求解。数位 DP 中,数的大小对复杂度的影响很小。
55
+
56
+ 对于区间 $[ l, r] $ 问题,我们一般会将其转化为 $[ 1, r] $ 问题,然后再减去 $[ 1, l - 1] $ 问题,即:
57
+
58
+ $$
59
+ ans = \sum_{i=1}^{r} ans_i - \sum_{i=1}^{l-1} ans_i
60
+ $$
61
+
62
+ 不过对于本题而言,我们只需要求出区间 $[ 1, r] $ 的值即可。
63
+
64
+ 这里我们用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。
65
+
66
+ 基本步骤如下:
67
+
68
+ 1 . 将数字 $x$ 转为 int 数组 $a$,其中 $a[ 1] $ 为最低位,而 $a[ len] $ 为最高位;
69
+ 1 . 根据题目信息,设计函数 $dfs()$,对于本题,我们定义 $dfs(pos, ok, limit)$,答案为 $dfs(len, 0, true)$。
70
+
71
+ 其中:
72
+
73
+ - ` pos ` 表示数字的位数,从末位或者第一位开始,一般根据题目的数字构造性质来选择顺序。对于本题,我们选择从高位开始,因此,` pos ` 的初始值为 ` len ` ;
74
+ - ` ok ` 表示当前数字是否满足题目要求(对于本题,如果数字出现 ` 2, 5, 6, 9 ` 则满足)
75
+ - ` limit ` 表示可填的数字的限制,如果无限制,那么可以选择 $[ 0, 9] $,否则,只能选择 $[ 0, a[ pos]] $。如果 ` limit ` 为 ` true ` 且已经取到了能取到的最大值,那么下一个 ` limit ` 同样为 ` true ` ;如果 ` limit ` 为 ` true ` 但是还没有取到最大值,或者 ` limit ` 为 ` false ` ,那么下一个 ` limit ` 为 ` false ` 。
76
+
77
+ 关于函数的实现细节,可以参考下面的代码。
78
+
79
+ 时间复杂度 $O(\log n)$。
80
+
50
81
<!-- tabs:start -->
51
82
52
83
### ** Python3**
@@ -72,6 +103,31 @@ class Solution:
72
103
return sum (check(i) for i in range (1 , n + 1 ))
73
104
```
74
105
106
+ ``` python
107
+ class Solution :
108
+ def rotatedDigits (self , n : int ) -> int :
109
+ @cache
110
+ def dfs (pos , ok , limit ):
111
+ if pos <= 0 :
112
+ return ok
113
+ up = a[pos] if limit else 9
114
+ ans = 0
115
+ for i in range (up + 1 ):
116
+ if i in (0 , 1 , 8 ):
117
+ ans += dfs(pos - 1 , ok, limit and i == up)
118
+ if i in (2 , 5 , 6 , 9 ):
119
+ ans += dfs(pos - 1 , 1 , limit and i == up)
120
+ return ans
121
+
122
+ a = [0 ] * 6
123
+ l = 1
124
+ while n:
125
+ a[l] = n % 10
126
+ n //= 10
127
+ l += 1
128
+ return dfs(l, 0 , True )
129
+ ```
130
+
75
131
### ** Java**
76
132
77
133
<!-- 这里可写当前语言的特殊实现逻辑 -->
@@ -116,6 +172,52 @@ class Solution {
116
172
}
117
173
```
118
174
175
+ ``` java
176
+ class Solution {
177
+ private int [] a = new int [6 ];
178
+ private int [][] dp = new int [6 ][2 ];
179
+
180
+ public int rotatedDigits (int n ) {
181
+ return f(n);
182
+ }
183
+
184
+ private int f (int x ) {
185
+ int len = 0 ;
186
+ for (var e : dp) {
187
+ Arrays . fill(e, - 1 );
188
+ }
189
+ while (x > 0 ) {
190
+ a[++ len] = x % 10 ;
191
+ x /= 10 ;
192
+ }
193
+ return dfs(len, 0 , true );
194
+ }
195
+
196
+ private int dfs (int pos , int ok , boolean limit ) {
197
+ if (pos <= 0 ) {
198
+ return ok;
199
+ }
200
+ if (! limit && dp[pos][ok] != - 1 ) {
201
+ return dp[pos][ok];
202
+ }
203
+ int up = limit ? a[pos] : 9 ;
204
+ int ans = 0 ;
205
+ for (int i = 0 ; i <= up; ++ i) {
206
+ if (i == 0 || i == 1 || i == 8 ) {
207
+ ans += dfs(pos - 1 , ok, limit && i == up);
208
+ }
209
+ if (i == 2 || i == 5 || i == 6 || i == 9 ) {
210
+ ans += dfs(pos - 1 , 1 , limit && i == up);
211
+ }
212
+ }
213
+ if (! limit) {
214
+ dp[pos][ok] = ans;
215
+ }
216
+ return ans;
217
+ }
218
+ }
219
+ ```
220
+
119
221
### ** C++**
120
222
121
223
``` cpp
@@ -148,6 +250,52 @@ public:
148
250
};
149
251
```
150
252
253
+ ```cpp
254
+ class Solution {
255
+ public:
256
+ int a[6];
257
+ int dp[6][2];
258
+
259
+ int rotatedDigits(int n) {
260
+ return f(n);
261
+ }
262
+
263
+ int f(int x) {
264
+ memset(dp, -1, sizeof dp);
265
+ int len = 0;
266
+ while (x) {
267
+ a[++len] = x % 10;
268
+ x /= 10;
269
+ }
270
+ return dfs(len, 0, true);
271
+ }
272
+
273
+ int dfs(int pos, int ok, bool limit) {
274
+ if (pos <= 0) {
275
+ return ok;
276
+ }
277
+ if (!limit && dp[pos][ok] != -1) {
278
+ return dp[pos][ok];
279
+ }
280
+ int up = limit ? a[pos] : 9;
281
+ int ans = 0;
282
+ for (int i = 0; i <= up; ++i) {
283
+ if (i == 0 || i == 1 || i == 8) {
284
+ ans += dfs(pos - 1, ok, limit && i == up);
285
+ }
286
+ if (i == 2 || i == 5 || i == 6 || i == 9) {
287
+ ans += dfs(pos - 1, 1, limit && i == up);
288
+ }
289
+ }
290
+ if (!limit) {
291
+ dp[pos][ok] = ans;
292
+ }
293
+ return ans;
294
+ }
295
+
296
+ };
297
+ ```
298
+
151
299
### ** Go**
152
300
153
301
``` go
@@ -176,6 +324,54 @@ func rotatedDigits(n int) int {
176
324
}
177
325
```
178
326
327
+ ``` go
328
+ func rotatedDigits (n int ) int {
329
+ a := make ([]int , 6 )
330
+ dp := make ([][]int , 6 )
331
+ for i := range a {
332
+ dp[i] = make ([]int , 2 )
333
+ for j := range dp[i] {
334
+ dp[i][j] = -1
335
+ }
336
+ }
337
+ l := 1
338
+ for n > 0 {
339
+ a[l] = n % 10
340
+ n /= 10
341
+ l++
342
+ }
343
+
344
+ var dfs func (int , int , bool ) int
345
+ dfs = func (pos, ok int , limit bool ) int {
346
+ if pos <= 0 {
347
+ return ok
348
+ }
349
+ if !limit && dp[pos][ok] != -1 {
350
+ return dp[pos][ok]
351
+ }
352
+ up := 9
353
+ if limit {
354
+ up = a[pos]
355
+ }
356
+ ans := 0
357
+ for i := 0 ; i <= up; i++ {
358
+ if i == 0 || i == 1 || i == 8 {
359
+ ans += dfs (pos-1 , ok, limit && i == up)
360
+ }
361
+ if i == 2 || i == 5 || i == 6 || i == 9 {
362
+ ans += dfs (pos-1 , 1 , limit && i == up)
363
+ }
364
+ }
365
+ if !limit {
366
+ dp[pos][ok] = ans
367
+ }
368
+ return ans
369
+ }
370
+
371
+ return dfs (l, 0 , true )
372
+ }
373
+ ```
374
+
179
375
### ** ...**
180
376
181
377
```
0 commit comments