Skip to content

Commit cc645a0

Browse files
committed
feat: add solutions to lc problem: No.1067
No.1067.Digit Count in Range
1 parent 117c623 commit cc645a0

File tree

6 files changed

+539
-1
lines changed

6 files changed

+539
-1
lines changed

solution/1000-1099/1067.Digit Count in Range/README.md

+202
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,224 @@
3939

4040
<!-- 这里可写通用的实现逻辑 -->
4141

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

4474
### **Python3**
4575

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

4878
```python
79+
class Solution:
80+
def digitsCount(self, d: int, low: int, high: int) -> int:
81+
return self.f(high, d) - self.f(low - 1, d)
82+
83+
def f(self, n, d):
84+
@cache
85+
def dfs(pos, cnt, lead, limit):
86+
if pos <= 0:
87+
return cnt
88+
up = a[pos] if limit else 9
89+
ans = 0
90+
for i in range(up + 1):
91+
if i == 0 and lead:
92+
ans += dfs(pos - 1, cnt, lead, limit and i == up)
93+
else:
94+
ans += dfs(pos - 1, cnt + (i == d),
95+
False, limit and i == up)
96+
return ans
4997

98+
a = [0] * 11
99+
l = 0
100+
while n:
101+
l += 1
102+
a[l] = n % 10
103+
n //= 10
104+
return dfs(l, 0, True, True)
50105
```
51106

52107
### **Java**
53108

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

56111
```java
112+
class Solution {
113+
private int d;
114+
private int[] a = new int[11];
115+
private int[][] dp = new int[11][11];
116+
117+
public int digitsCount(int d, int low, int high) {
118+
this.d = d;
119+
return f(high) - f(low - 1);
120+
}
121+
122+
private int f(int n) {
123+
for (var e : dp) {
124+
Arrays.fill(e, -1);
125+
}
126+
int len = 0;
127+
while (n > 0) {
128+
a[++len] = n % 10;
129+
n /= 10;
130+
}
131+
return dfs(len, 0, true, true);
132+
}
133+
134+
private int dfs(int pos, int cnt, boolean lead, boolean limit) {
135+
if (pos <= 0) {
136+
return cnt;
137+
}
138+
if (!lead && !limit && dp[pos][cnt] != -1) {
139+
return dp[pos][cnt];
140+
}
141+
int up = limit ? a[pos] : 9;
142+
int ans = 0;
143+
for (int i = 0; i <= up; ++i) {
144+
if (i == 0 && lead) {
145+
ans += dfs(pos - 1, cnt, lead, limit && i == up);
146+
} else {
147+
ans += dfs(pos - 1, cnt + (i == d ? 1 : 0), false, limit && i == up);
148+
}
149+
}
150+
if (!lead && !limit) {
151+
dp[pos][cnt] = ans;
152+
}
153+
return ans;
154+
}
155+
}
156+
```
157+
158+
### **C++**
159+
160+
```cpp
161+
class Solution {
162+
public:
163+
int d;
164+
int a[11];
165+
int dp[11][11];
166+
167+
int digitsCount(int d, int low, int high) {
168+
this->d = d;
169+
return f(high) - f(low - 1);
170+
}
171+
172+
int f(int n) {
173+
memset(dp, -1, sizeof dp);
174+
int len = 0;
175+
while (n) {
176+
a[++len] = n % 10;
177+
n /= 10;
178+
}
179+
return dfs(len, 0, true, true);
180+
}
181+
182+
int dfs(int pos, int cnt, bool lead, bool limit) {
183+
if (pos <= 0) {
184+
return cnt;
185+
}
186+
if (!lead && !limit && dp[pos][cnt] != -1) {
187+
return dp[pos][cnt];
188+
}
189+
int up = limit ? a[pos] : 9;
190+
int ans = 0;
191+
for (int i = 0; i <= up; ++i) {
192+
if (i == 0 && lead) {
193+
ans += dfs(pos - 1, cnt, lead, limit && i == up);
194+
} else {
195+
ans += dfs(pos - 1, cnt + (i == d), false, limit && i == up);
196+
}
197+
}
198+
if (!lead && !limit) {
199+
dp[pos][cnt] = ans;
200+
}
201+
return ans;
202+
}
203+
};
204+
```
205+
206+
### **Go**
207+
208+
```go
209+
func digitsCount(d int, low int, high int) int {
210+
f := func(n int) int {
211+
a := make([]int, 11)
212+
dp := make([][]int, 11)
213+
for i := range dp {
214+
dp[i] = make([]int, 11)
215+
for j := range dp[i] {
216+
dp[i][j] = -1
217+
}
218+
}
219+
l := 0
220+
for n > 0 {
221+
l++
222+
a[l] = n % 10
223+
n /= 10
224+
}
225+
226+
var dfs func(int, int, bool, bool) int
227+
dfs = func(pos, cnt int, lead, limit bool) int {
228+
if pos <= 0 {
229+
return cnt
230+
}
231+
if !lead && !limit && dp[pos][cnt] != -1 {
232+
return dp[pos][cnt]
233+
}
234+
up := 9
235+
if limit {
236+
up = a[pos]
237+
}
238+
ans := 0
239+
for i := 0; i <= up; i++ {
240+
if i == 0 && lead {
241+
ans += dfs(pos-1, cnt, lead, limit && i == up)
242+
} else {
243+
t := cnt
244+
if d == i {
245+
t++
246+
}
247+
ans += dfs(pos-1, t, false, limit && i == up)
248+
}
249+
}
250+
if !lead && !limit {
251+
dp[pos][cnt] = ans
252+
}
253+
return ans
254+
}
57255
256+
return dfs(l, 0, true, true)
257+
}
258+
return f(high) - f(low-1)
259+
}
58260
```
59261

60262
### **...**

0 commit comments

Comments
 (0)