Skip to content

Commit 7ab6a88

Browse files
committed
feat: add solutions to lcci problem: No.17.06
No.17.06.Number Of 2s In Range
1 parent 94c1156 commit 7ab6a88

File tree

6 files changed

+434
-2
lines changed

6 files changed

+434
-2
lines changed

lcci/17.06.Number Of 2s In Range/README.md

Lines changed: 169 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
## 题目描述
66

77
<!-- 这里写题目描述 -->
8+
89
<p>编写一个方法,计算从 0 到 n (含 n) 中数字 2 出现的次数。</p>
910
<p><strong>示例:</strong></p>
1011
<pre><strong>输入: </strong>25
@@ -19,22 +20,189 @@
1920

2021
<!-- 这里可写通用的实现逻辑 -->
2122

23+
**方法一:数位 DP**
24+
25+
这道题实际上是求在给定区间 $[l,..r]$ 中,数字中出现 $2$ 个数。个数与数的位数以及每一位上的数字有关。我们可以用数位 DP 的思路来解决这道题。数位 DP 中,数的大小对复杂度的影响很小。
26+
27+
对于区间 $[l,..r]$ 问题,我们一般会将其转化为 $[1,..r]$ 然后再减去 $[1,..l - 1]$ 的问题,即:
28+
29+
$$
30+
ans = \sum_{i=1}^{r} ans_i - \sum_{i=1}^{l-1} ans_i
31+
$$
32+
33+
不过对于本题而言,我们只需要求出区间 $[1,..r]$ 的值即可。
34+
35+
这里我们用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。
36+
37+
基本步骤如下:
38+
39+
1. 将数字 $n$ 转为 int 数组 $a$,其中 $a[1]$ 为最低位,而 $a[len]$ 为最高位;
40+
1. 根据题目信息,设计函数 $dfs()$,对于本题,我们定义 $dfs(pos, cnt, limit)$,答案为 $dfs(len, 0, true)$。
41+
42+
其中:
43+
44+
- `pos` 表示数字的位数,从末位或者第一位开始,一般根据题目的数字构造性质来选择顺序。对于本题,我们选择从高位开始,因此,`pos` 的初始值为 `len`
45+
- `cnt` 表示当前数字中包含的 $2$ 的个数。
46+
- `limit` 表示可填的数字的限制,如果无限制,那么可以选择 $[0,1,..9]$,否则,只能选择 $[0,..a[pos]]$。如果 `limit``true` 且已经取到了能取到的最大值,那么下一个 `limit` 同样为 `true`;如果 `limit``true` 但是还没有取到最大值,或者 `limit``false`,那么下一个 `limit``false`
47+
48+
关于函数的实现细节,可以参考下面的代码。
49+
50+
时间复杂度 $O(\log n)$。
51+
52+
相似题目:[233. 数字 1 的个数](/solution/0200-0299/0233.Number%20of%20Digit%20One/README.md)
53+
2254
<!-- tabs:start -->
2355

2456
### **Python3**
2557

2658
<!-- 这里可写当前语言的特殊实现逻辑 -->
2759

2860
```python
29-
61+
class Solution:
62+
def numberOf2sInRange(self, n: int) -> int:
63+
@cache
64+
def dfs(pos, cnt, limit):
65+
if pos <= 0:
66+
return cnt
67+
up = a[pos] if limit else 9
68+
ans = 0
69+
for i in range(up + 1):
70+
ans += dfs(pos - 1, cnt + (i == 2), limit and i == up)
71+
return ans
72+
73+
a = [0] * 12
74+
l = 1
75+
while n:
76+
a[l] = n % 10
77+
n //= 10
78+
l += 1
79+
return dfs(l, 0, True)
3080
```
3181

3282
### **Java**
3383

3484
<!-- 这里可写当前语言的特殊实现逻辑 -->
3585

3686
```java
87+
class Solution {
88+
private int[] a = new int[12];
89+
private int[][] dp = new int[12][12];
90+
91+
public int numberOf2sInRange(int n) {
92+
int len = 1;
93+
while (n > 0) {
94+
a[len++] = n % 10;
95+
n /= 10;
96+
}
97+
for (var e : dp) {
98+
Arrays.fill(e, -1);
99+
}
100+
return dfs(len, 0, true);
101+
}
102+
103+
private int dfs(int pos, int cnt, boolean limit) {
104+
if (pos <= 0) {
105+
return cnt;
106+
}
107+
if (!limit && dp[pos][cnt] != -1) {
108+
return dp[pos][cnt];
109+
}
110+
int up = limit ? a[pos] : 9;
111+
int ans = 0;
112+
for (int i = 0; i <= up; ++i) {
113+
ans += dfs(pos - 1, cnt + (i == 2 ? 1 : 0), limit && i == up);
114+
}
115+
if (!limit) {
116+
dp[pos][cnt] = ans;
117+
}
118+
return ans;
119+
}
120+
}
121+
```
122+
123+
### **C++**
124+
125+
```cpp
126+
class Solution {
127+
public:
128+
int a[12];
129+
int dp[12][12];
130+
131+
int numberOf2sInRange(int n) {
132+
int len = 1;
133+
while (n) {
134+
a[len++] = n % 10;
135+
n /= 10;
136+
}
137+
memset(dp, -1, sizeof dp);
138+
return dfs(len, 0, true);
139+
}
140+
141+
int dfs(int pos, int cnt, bool limit) {
142+
if (pos <= 0) {
143+
return cnt;
144+
}
145+
if (!limit && dp[pos][cnt] != -1) {
146+
return dp[pos][cnt];
147+
}
148+
int ans = 0;
149+
int up = limit ? a[pos] : 9;
150+
for (int i = 0; i <= up; ++i) {
151+
ans += dfs(pos - 1, cnt + (i == 2), limit && i == up);
152+
}
153+
if (!limit) {
154+
dp[pos][cnt] = ans;
155+
}
156+
return ans;
157+
}
158+
};
159+
```
37160
161+
### **Go**
162+
163+
```go
164+
func numberOf2sInRange(n int) int {
165+
a := make([]int, 12)
166+
dp := make([][]int, 12)
167+
for i := range dp {
168+
dp[i] = make([]int, 12)
169+
for j := range dp[i] {
170+
dp[i][j] = -1
171+
}
172+
}
173+
l := 1
174+
for n > 0 {
175+
a[l] = n % 10
176+
n /= 10
177+
l++
178+
}
179+
var dfs func(int, int, bool) int
180+
dfs = func(pos, cnt int, limit bool) int {
181+
if pos <= 0 {
182+
return cnt
183+
}
184+
if !limit && dp[pos][cnt] != -1 {
185+
return dp[pos][cnt]
186+
}
187+
up := 9
188+
if limit {
189+
up = a[pos]
190+
}
191+
ans := 0
192+
for i := 0; i <= up; i++ {
193+
t := cnt
194+
if i == 2 {
195+
t++
196+
}
197+
ans += dfs(pos-1, t, limit && i == up)
198+
}
199+
if !limit {
200+
dp[pos][cnt] = ans
201+
}
202+
return ans
203+
}
204+
return dfs(l, 0, true)
205+
}
38206
```
39207

40208
### **...**

lcci/17.06.Number Of 2s In Range/README_EN.md

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,149 @@
2626
### **Python3**
2727

2828
```python
29-
29+
class Solution:
30+
def numberOf2sInRange(self, n: int) -> int:
31+
@cache
32+
def dfs(pos, cnt, limit):
33+
if pos <= 0:
34+
return cnt
35+
up = a[pos] if limit else 9
36+
ans = 0
37+
for i in range(up + 1):
38+
ans += dfs(pos - 1, cnt + (i == 2), limit and i == up)
39+
return ans
40+
41+
a = [0] * 12
42+
l = 1
43+
while n:
44+
a[l] = n % 10
45+
n //= 10
46+
l += 1
47+
return dfs(l, 0, True)
3048
```
3149

3250
### **Java**
3351

3452
```java
53+
class Solution {
54+
private int[] a = new int[12];
55+
private int[][] dp = new int[12][12];
56+
57+
public int numberOf2sInRange(int n) {
58+
int len = 1;
59+
while (n > 0) {
60+
a[len++] = n % 10;
61+
n /= 10;
62+
}
63+
for (var e : dp) {
64+
Arrays.fill(e, -1);
65+
}
66+
return dfs(len, 0, true);
67+
}
68+
69+
private int dfs(int pos, int cnt, boolean limit) {
70+
if (pos <= 0) {
71+
return cnt;
72+
}
73+
if (!limit && dp[pos][cnt] != -1) {
74+
return dp[pos][cnt];
75+
}
76+
int up = limit ? a[pos] : 9;
77+
int ans = 0;
78+
for (int i = 0; i <= up; ++i) {
79+
ans += dfs(pos - 1, cnt + (i == 2 ? 1 : 0), limit && i == up);
80+
}
81+
if (!limit) {
82+
dp[pos][cnt] = ans;
83+
}
84+
return ans;
85+
}
86+
}
87+
```
88+
89+
### **C++**
90+
91+
```cpp
92+
class Solution {
93+
public:
94+
int a[12];
95+
int dp[12][12];
96+
97+
int numberOf2sInRange(int n) {
98+
int len = 1;
99+
while (n) {
100+
a[len++] = n % 10;
101+
n /= 10;
102+
}
103+
memset(dp, -1, sizeof dp);
104+
return dfs(len, 0, true);
105+
}
106+
107+
int dfs(int pos, int cnt, bool limit) {
108+
if (pos <= 0) {
109+
return cnt;
110+
}
111+
if (!limit && dp[pos][cnt] != -1) {
112+
return dp[pos][cnt];
113+
}
114+
int ans = 0;
115+
int up = limit ? a[pos] : 9;
116+
for (int i = 0; i <= up; ++i) {
117+
ans += dfs(pos - 1, cnt + (i == 2), limit && i == up);
118+
}
119+
if (!limit) {
120+
dp[pos][cnt] = ans;
121+
}
122+
return ans;
123+
}
124+
};
125+
```
35126
127+
### **Go**
128+
129+
```go
130+
func numberOf2sInRange(n int) int {
131+
a := make([]int, 12)
132+
dp := make([][]int, 12)
133+
for i := range dp {
134+
dp[i] = make([]int, 12)
135+
for j := range dp[i] {
136+
dp[i][j] = -1
137+
}
138+
}
139+
l := 1
140+
for n > 0 {
141+
a[l] = n % 10
142+
n /= 10
143+
l++
144+
}
145+
var dfs func(int, int, bool) int
146+
dfs = func(pos, cnt int, limit bool) int {
147+
if pos <= 0 {
148+
return cnt
149+
}
150+
if !limit && dp[pos][cnt] != -1 {
151+
return dp[pos][cnt]
152+
}
153+
up := 9
154+
if limit {
155+
up = a[pos]
156+
}
157+
ans := 0
158+
for i := 0; i <= up; i++ {
159+
t := cnt
160+
if i == 2 {
161+
t++
162+
}
163+
ans += dfs(pos-1, t, limit && i == up)
164+
}
165+
if !limit {
166+
dp[pos][cnt] = ans
167+
}
168+
return ans
169+
}
170+
return dfs(l, 0, true)
171+
}
36172
```
37173

38174
### **...**
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
class Solution {
2+
public:
3+
int a[12];
4+
int dp[12][12];
5+
6+
int numberOf2sInRange(int n) {
7+
int len = 1;
8+
while (n) {
9+
a[len++] = n % 10;
10+
n /= 10;
11+
}
12+
memset(dp, -1, sizeof dp);
13+
return dfs(len, 0, true);
14+
}
15+
16+
int dfs(int pos, int cnt, bool limit) {
17+
if (pos <= 0) {
18+
return cnt;
19+
}
20+
if (!limit && dp[pos][cnt] != -1) {
21+
return dp[pos][cnt];
22+
}
23+
int ans = 0;
24+
int up = limit ? a[pos] : 9;
25+
for (int i = 0; i <= up; ++i) {
26+
ans += dfs(pos - 1, cnt + (i == 2), limit && i == up);
27+
}
28+
if (!limit) {
29+
dp[pos][cnt] = ans;
30+
}
31+
return ans;
32+
}
33+
};

0 commit comments

Comments
 (0)