Skip to content

Commit 5223b63

Browse files
committed
feat: add solutions to lc problem: No.0233
No.0233.Number of Digit One
1 parent c238c6b commit 5223b63

File tree

8 files changed

+398
-294
lines changed

8 files changed

+398
-294
lines changed

solution/0200-0299/0233.Number of Digit One/README.md

Lines changed: 127 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,22 @@ $$
6666

6767
基本步骤如下:
6868

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})$,其中:
7170

72-
其中:
71+
- 数字 $i$ 表示当前搜索到的位置,我们从高位开始搜索,即 $i = 0$ 表示最高位。
72+
- 数字 $\textit{cnt}$ 表示当前数字中 $1$ 出现的次数。
73+
- 布尔值 $\textit{limit}$ 表示当前是否受到上界的限制。
7374

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+
函数的执行过程如下:
7776

78-
关于函数的实现细节,可以参考下面的代码。
77+
如果 $i$ 超过了数字 $n$ 的长度,说明搜索结束,直接返回 $cnt$。如果 $\textit{limit}$ 为真,$up$ 为当前数字的第 $i$ 位,否则 $up = 9$。接下来,我们遍历 $j$ 从 $0$ 到 $up$,对于每一个 $j$:
7978

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$。
8185

8286
相似题目:
8387

@@ -96,57 +100,48 @@ $$
96100
class Solution:
97101
def countDigitOne(self, n: int) -> int:
98102
@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):
101105
return cnt
102-
up = a[pos] if limit else 9
106+
up = int(s[i]) if limit else 9
103107
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)
106110
return ans
107111

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)
115114
```
116115

117116
#### Java
118117

119118
```java
120119
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;
123123

124124
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);
134129
}
135130

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) {
138133
return cnt;
139134
}
140-
if (!limit && dp[pos][cnt] != -1) {
141-
return dp[pos][cnt];
135+
if (!limit && f[i][cnt] != null) {
136+
return f[i][cnt];
142137
}
143-
int up = limit ? a[pos] : 9;
138+
int up = limit ? s[i] - '0' : 9;
144139
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);
147142
}
148143
if (!limit) {
149-
dp[pos][cnt] = ans;
144+
f[i][cnt] = ans;
150145
}
151146
return ans;
152147
}
@@ -158,35 +153,29 @@ class Solution {
158153
```cpp
159154
class Solution {
160155
public:
161-
int a[12];
162-
int dp[12][12];
163-
164156
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);
190179
}
191180
};
192181
```
@@ -195,67 +184,103 @@ public:
195184
196185
```go
197186
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
204194
}
205195
}
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 {
215199
return cnt
216200
}
217-
if !limit && dp[pos][cnt] != -1 {
218-
return dp[pos][cnt]
201+
if !limit && f[i][cnt] != -1 {
202+
return f[i][cnt]
219203
}
220204
up := 9
221205
if limit {
222-
up = a[pos]
206+
up = int(s[i] - '0')
223207
}
224208
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
229213
}
230-
ans += dfs(pos-1, t, limit && i == up)
214+
ans += dfs(i+1, cnt+t, limit && j == up)
231215
}
232216
if !limit {
233-
dp[pos][cnt] = ans
217+
f[i][cnt] = ans
234218
}
235219
return ans
236220
}
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);
238250
}
239251
```
240252

241253
#### C#
242254

243255
```cs
244256
public class Solution {
257+
private int m;
258+
private char[] s;
259+
private int?[,] f;
260+
245261
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);
249266
}
250267

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;
257271
}
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;
259284
}
260285
}
261286
```

0 commit comments

Comments
 (0)