66
66
67
67
基本步骤如下:
68
68
69
- 1 . 将数字 $n$ 转为 int 数组 $a$,其中 $a[ 1] $ 为最低位,而 $a[ len] $ 为最高位;
70
- 1 . 根据题目信息,设计函数 $dfs()$,对于本题,我们定义 $dfs(pos, cnt, limit)$,答案为 $dfs(len, 0, true)$。
69
+ 我们首先将数字 $n$ 转化为字符串 $s$。然后我们设计一个函数 $\textit{dfs}(i, \textit{cnt}, \textit{limit})$,其中:
71
70
72
- 其中:
71
+ - 数字 $i$ 表示当前搜索到的位置,我们从高位开始搜索,即 $i = 0$ 表示最高位。
72
+ - 数字 $\textit{cnt}$ 表示当前数字中 $1$ 出现的次数。
73
+ - 布尔值 $\textit{limit}$ 表示当前是否受到上界的限制。
73
74
74
- - ` pos ` 表示数字的位数,从末位或者第一位开始,一般根据题目的数字构造性质来选择顺序。对于本题,我们选择从高位开始,因此,` pos ` 的初始值为 ` len ` ;
75
- - ` cnt ` 表示当前数字中包含的 $1$ 的个数。
76
- - ` limit ` 表示可填的数字的限制,如果无限制,那么可以选择 $[ 0,1,..9] $,否则,只能选择 $[ 0,..a[ pos]] $。如果 ` limit ` 为 ` true ` 且已经取到了能取到的最大值,那么下一个 ` limit ` 同样为 ` true ` ;如果 ` limit ` 为 ` true ` 但是还没有取到最大值,或者 ` limit ` 为 ` false ` ,那么下一个 ` limit ` 为 ` false ` 。
75
+ 函数的执行过程如下:
77
76
78
- 关于函数的实现细节,可以参考下面的代码。
77
+ 如果 $i$ 超过了数字 $n$ 的长度,说明搜索结束,直接返回 $cnt$。如果 $\textit{limit}$ 为真,$up$ 为当前数字的第 $i$ 位,否则 $up = 9$。接下来,我们遍历 $j$ 从 $0$ 到 $up$,对于每一个 $j$:
79
78
80
- 时间复杂度 $O(\log n)$。
79
+ - 如果 $j$ 等于 $1$,我们将 $cnt$ 加一。
80
+ - 递归调用 $\textit{dfs}(i + 1, \textit{cnt}, \textit{limit} \&\& j == up)$。
81
+
82
+ 答案为 $\textit{dfs}(0, 0, \text{True})$。
83
+
84
+ 时间复杂度 $O(m^2 \times D)$,空间复杂度 $O(m^2)$。其中 $m$ 为数字 $n$ 的长度,而 $D = 10$。
81
85
82
86
相似题目:
83
87
96
100
class Solution :
97
101
def countDigitOne (self , n : int ) -> int :
98
102
@cache
99
- def dfs (pos , cnt , limit ) :
100
- if pos <= 0 :
103
+ def dfs (i : int , cnt : int , limit : bool ) -> int :
104
+ if i >= len (s) :
101
105
return cnt
102
- up = a[pos] if limit else 9
106
+ up = int (s[i]) if limit else 9
103
107
ans = 0
104
- for i in range (up + 1 ):
105
- ans += dfs(pos - 1 , cnt + (i == 1 ), limit and i == up)
108
+ for j in range (up + 1 ):
109
+ ans += dfs(i + 1 , cnt + (j == 1 ), limit and j == up)
106
110
return ans
107
111
108
- a = [0 ] * 12
109
- l = 1
110
- while n:
111
- a[l] = n % 10
112
- n //= 10
113
- l += 1
114
- return dfs(l, 0 , True )
112
+ s = str (n)
113
+ return dfs(0 , 0 , True )
115
114
```
116
115
117
116
#### Java
118
117
119
118
``` java
120
119
class Solution {
121
- private int [] a = new int [12 ];
122
- private int [][] dp = new int [12 ][12 ];
120
+ private int m;
121
+ private char [] s;
122
+ private Integer [][] f;
123
123
124
124
public int countDigitOne (int n ) {
125
- int len = 0 ;
126
- while (n > 0 ) {
127
- a[++ len] = n % 10 ;
128
- n /= 10 ;
129
- }
130
- for (var e : dp) {
131
- Arrays . fill(e, - 1 );
132
- }
133
- return dfs(len, 0 , true );
125
+ s = String . valueOf(n). toCharArray();
126
+ m = s. length;
127
+ f = new Integer [m][m];
128
+ return dfs(0 , 0 , true );
134
129
}
135
130
136
- private int dfs (int pos , int cnt , boolean limit ) {
137
- if (pos <= 0 ) {
131
+ private int dfs (int i , int cnt , boolean limit ) {
132
+ if (i >= m ) {
138
133
return cnt;
139
134
}
140
- if (! limit && dp[pos ][cnt] != - 1 ) {
141
- return dp[pos ][cnt];
135
+ if (! limit && f[i ][cnt] != null ) {
136
+ return f[i ][cnt];
142
137
}
143
- int up = limit ? a[pos] : 9 ;
138
+ int up = limit ? s[i] - ' 0 ' : 9 ;
144
139
int ans = 0 ;
145
- for (int i = 0 ; i <= up; ++ i ) {
146
- ans += dfs(pos - 1 , cnt + (i == 1 ? 1 : 0 ), limit && i == up);
140
+ for (int j = 0 ; j <= up; ++ j ) {
141
+ ans += dfs(i + 1 , cnt + (j == 1 ? 1 : 0 ), limit && j == up);
147
142
}
148
143
if (! limit) {
149
- dp[pos ][cnt] = ans;
144
+ f[i ][cnt] = ans;
150
145
}
151
146
return ans;
152
147
}
@@ -158,35 +153,29 @@ class Solution {
158
153
``` cpp
159
154
class Solution {
160
155
public:
161
- int a[ 12] ;
162
- int dp[ 12] [ 12 ] ;
163
-
164
156
int countDigitOne(int n) {
165
- int len = 0;
166
- while (n) {
167
- a[++len] = n % 10;
168
- n /= 10;
169
- }
170
- memset (dp, -1, sizeof dp);
171
- return dfs(len, 0, true);
172
- }
173
-
174
- int dfs(int pos, int cnt, bool limit) {
175
- if (pos <= 0) {
176
- return cnt;
177
- }
178
- if (!limit && dp[pos][cnt] != -1) {
179
- return dp[pos][cnt];
180
- }
181
- int ans = 0;
182
- int up = limit ? a[pos] : 9;
183
- for (int i = 0; i <= up; ++i) {
184
- ans += dfs(pos - 1, cnt + (i == 1), limit && i == up);
185
- }
186
- if (!limit) {
187
- dp[pos][cnt] = ans;
188
- }
189
- return ans;
157
+ string s = to_string(n);
158
+ int m = s.size();
159
+ int f[ m] [ m ] ;
160
+ memset(f, -1, sizeof(f));
161
+ auto dfs = [ &] (auto&& dfs, int i, int cnt, bool limit) -> int {
162
+ if (i >= m) {
163
+ return cnt;
164
+ }
165
+ if (!limit && f[ i] [ cnt ] != -1) {
166
+ return f[ i] [ cnt ] ;
167
+ }
168
+ int up = limit ? s[ i] - '0' : 9;
169
+ int ans = 0;
170
+ for (int j = 0; j <= up; ++j) {
171
+ ans += dfs(dfs, i + 1, cnt + (j == 1), limit && j == up);
172
+ }
173
+ if (!limit) {
174
+ f[ i] [ cnt ] = ans;
175
+ }
176
+ return ans;
177
+ };
178
+ return dfs(dfs, 0, 0, true);
190
179
}
191
180
};
192
181
```
@@ -195,67 +184,103 @@ public:
195
184
196
185
```go
197
186
func countDigitOne(n int) int {
198
- a := make([]int, 12)
199
- dp := make([][]int, 12)
200
- for i := range dp {
201
- dp[i] = make([]int, 12)
202
- for j := range dp[i] {
203
- dp[i][j] = -1
187
+ s := strconv.Itoa(n)
188
+ m := len(s)
189
+ f := make([][]int, m)
190
+ for i := range f {
191
+ f[i] = make([]int, m)
192
+ for j := range f[i] {
193
+ f[i][j] = -1
204
194
}
205
195
}
206
- l := 0
207
- for n > 0 {
208
- l++
209
- a[l] = n % 10
210
- n /= 10
211
- }
212
- var dfs func(int, int, bool) int
213
- dfs = func(pos, cnt int, limit bool) int {
214
- if pos <= 0 {
196
+ var dfs func(i, cnt int, limit bool) int
197
+ dfs = func(i, cnt int, limit bool) int {
198
+ if i >= m {
215
199
return cnt
216
200
}
217
- if !limit && dp[pos ][cnt] != -1 {
218
- return dp[pos ][cnt]
201
+ if !limit && f[i ][cnt] != -1 {
202
+ return f[i ][cnt]
219
203
}
220
204
up := 9
221
205
if limit {
222
- up = a[pos]
206
+ up = int(s[i] - '0')
223
207
}
224
208
ans := 0
225
- for i := 0; i <= up; i ++ {
226
- t := cnt
227
- if i == 1 {
228
- t++
209
+ for j := 0; j <= up; j ++ {
210
+ t := 0
211
+ if j == 1 {
212
+ t = 1
229
213
}
230
- ans += dfs(pos- 1, t, limit && i == up)
214
+ ans += dfs(i+ 1, cnt+ t, limit && j == up)
231
215
}
232
216
if !limit {
233
- dp[pos ][cnt] = ans
217
+ f[i ][cnt] = ans
234
218
}
235
219
return ans
236
220
}
237
- return dfs(l, 0, true)
221
+ return dfs(0, 0, true)
222
+ }
223
+ ```
224
+
225
+ #### TypeScript
226
+
227
+ ``` ts
228
+ function countDigitOne(n : number ): number {
229
+ const s = n .toString ();
230
+ const m = s .length ;
231
+ const f: number [][] = Array .from ({ length: m }, () => Array (m ).fill (- 1 ));
232
+ const dfs = (i : number , cnt : number , limit : boolean ): number => {
233
+ if (i >= m ) {
234
+ return cnt ;
235
+ }
236
+ if (! limit && f [i ][cnt ] !== - 1 ) {
237
+ return f [i ][cnt ];
238
+ }
239
+ const up = limit ? + s [i ] : 9 ;
240
+ let ans = 0 ;
241
+ for (let j = 0 ; j <= up ; ++ j ) {
242
+ ans += dfs (i + 1 , cnt + (j === 1 ? 1 : 0 ), limit && j === up );
243
+ }
244
+ if (! limit ) {
245
+ f [i ][cnt ] = ans ;
246
+ }
247
+ return ans ;
248
+ };
249
+ return dfs (0 , 0 , true );
238
250
}
239
251
```
240
252
241
253
#### C#
242
254
243
255
``` cs
244
256
public class Solution {
257
+ private int m ;
258
+ private char [] s ;
259
+ private int ?[,] f ;
260
+
245
261
public int CountDigitOne (int n ) {
246
- if (n <= 0 ) return 0 ;
247
- if (n < 10 ) return 1 ;
248
- return CountDigitOne (n / 10 - 1 ) * 10 + n / 10 + CountDigitOneOfN (n / 10 ) * (n % 10 + 1 ) + (n % 10 >= 1 ? 1 : 0 );
262
+ s = n .ToString ().ToCharArray ();
263
+ m = s .Length ;
264
+ f = new int ?[m , m ];
265
+ return Dfs (0 , 0 , true );
249
266
}
250
267
251
- private int CountDigitOneOfN (int n ) {
252
- var count = 0 ;
253
- while (n > 0 )
254
- {
255
- if (n % 10 == 1 ) ++ count ;
256
- n /= 10 ;
268
+ private int Dfs (int i , int cnt , bool limit ) {
269
+ if (i >= m ) {
270
+ return cnt ;
257
271
}
258
- return count ;
272
+ if (! limit && f [i , cnt ] != null ) {
273
+ return f [i , cnt ].Value ;
274
+ }
275
+ int up = limit ? s [i ] - '0' : 9 ;
276
+ int ans = 0 ;
277
+ for (int j = 0 ; j <= up ; ++ j ) {
278
+ ans += Dfs (i + 1 , cnt + (j == 1 ? 1 : 0 ), limit && j == up );
279
+ }
280
+ if (! limit ) {
281
+ f [i , cnt ] = ans ;
282
+ }
283
+ return ans ;
259
284
}
260
285
}
261
286
```
0 commit comments