Skip to content

Commit 297b0dc

Browse files
authored
feat: add solutions to lc problem: No.2999 (#4320)
1 parent e7ced26 commit 297b0dc

File tree

5 files changed

+190
-8
lines changed

5 files changed

+190
-8
lines changed

solution/2900-2999/2999.Count the Number of Powerful Integers/README.md

+74-3
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,33 @@ tags:
7474

7575
<!-- solution:start -->
7676

77-
### 方法一
77+
### 方法一:数位 DP
78+
79+
这道题实际上是求在给定区间 $[l,..r]$ 中,满足条件的数的个数。个数与数的位数以及每一位上的数字有关。我们可以用数位 DP 的思路来解决这道题。数位 DP 中,数的大小对复杂度的影响很小。
80+
81+
对于区间 $[l,..r]$ 问题,我们一般会将其转化为 $[1,..r]$ 然后再减去 $[1,..l - 1]$ 的问题,即:
82+
83+
$$
84+
ans = \sum_{i=1}^{r} ans_i - \sum_{i=1}^{l-1} ans_i
85+
$$
86+
87+
对于本题而言,我们求出 $[1, \textit{finish}]$ 中满足条件的数的个数,然后减去 $[1, \textit{start} - 1]$ 中满足条件的数的个数,即可得到答案。
88+
89+
这里我们用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。
90+
91+
基本步骤如下:
92+
93+
1. 先将 $\textit{start}$ 和 $\textit{finish}$ 转化为字符串,方便后续的数位 DP。
94+
2. 设计一个函数 $\textit{dfs}(\textit{pos}, \textit{lim})$,表示从第 $\textit{pos}$ 位开始搜索,当前的限制条件为 $\textit{lim}$。
95+
3. 如果最大的数字位数小于 $\textit{s}$ 的长度,返回 0。
96+
4. 如果当前剩余的数字位数等于 $\textit{s}$ 的长度,判断当前的数字是否满足条件,返回 1 或 0。
97+
5. 否则,我们计算当前位的上限 $\textit{up} = \min(\textit{lim} ? \textit{t}[\textit{pos}] : 9, \textit{limit})$。然后遍历当前位的数字 $i$,从 0 到 $\textit{up}$,递归调用 $\textit{dfs}(\textit{pos} + 1, \textit{lim} \&\& i == \textit{t}[\textit{pos}])$,将结果累加到答案中。
98+
6. 如果当前的 $\textit{lim}$ 为 false,则将当前的答案存入缓存中,避免重复计算。
99+
7. 最后返回答案。
100+
101+
答案为区间 $[1, \textit{finish}]$ 中满足条件的数的个数减去区间 $[1, \textit{start} - 1]$ 中满足条件的数的个数。
102+
103+
时间复杂度 $O(\log M \times D)$,空间复杂度 $O(\log M)$,其中 $M$ 为数字的上限,而 $D = 10$。
78104

79105
<!-- tabs:start -->
80106

@@ -84,7 +110,7 @@ tags:
84110
class Solution:
85111
def numberOfPowerfulInt(self, start: int, finish: int, limit: int, s: str) -> int:
86112
@cache
87-
def dfs(pos: int, lim: int):
113+
def dfs(pos: int, lim: int) -> int:
88114
if len(t) < n:
89115
return 0
90116
if len(t) - pos == n:
@@ -159,7 +185,7 @@ public:
159185
long long f[20];
160186
memset(f, -1, sizeof(f));
161187

162-
function<long long(int, bool)> dfs = [&](int pos, bool lim) -> long long {
188+
auto dfs = [&](this auto&& dfs, int pos, int lim) -> long long {
163189
if (t.size() < s.size()) {
164190
return 0;
165191
}
@@ -284,6 +310,51 @@ function numberOfPowerfulInt(start: number, finish: number, limit: number, s: st
284310
}
285311
```
286312

313+
#### C#
314+
315+
```cs
316+
public class Solution {
317+
private string s;
318+
private string t;
319+
private long?[] f;
320+
private int limit;
321+
322+
public long NumberOfPowerfulInt(long start, long finish, int limit, string s) {
323+
this.s = s;
324+
this.limit = limit;
325+
t = (start - 1).ToString();
326+
f = new long?[20];
327+
long a = Dfs(0, true);
328+
t = finish.ToString();
329+
f = new long?[20];
330+
long b = Dfs(0, true);
331+
return b - a;
332+
}
333+
334+
private long Dfs(int pos, bool lim) {
335+
if (t.Length < s.Length) {
336+
return 0;
337+
}
338+
if (!lim && f[pos].HasValue) {
339+
return f[pos].Value;
340+
}
341+
if (t.Length - pos == s.Length) {
342+
return lim ? (string.Compare(s, t.Substring(pos)) <= 0 ? 1 : 0) : 1;
343+
}
344+
int up = lim ? t[pos] - '0' : 9;
345+
up = Math.Min(up, limit);
346+
long ans = 0;
347+
for (int i = 0; i <= up; ++i) {
348+
ans += Dfs(pos + 1, lim && i == (t[pos] - '0'));
349+
}
350+
if (!lim) {
351+
f[pos] = ans;
352+
}
353+
return ans;
354+
}
355+
}
356+
```
357+
287358
<!-- tabs:end -->
288359

289360
<!-- solution:end -->

solution/2900-2999/2999.Count the Number of Powerful Integers/README_EN.md

+74-3
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,33 @@ It can be shown that there are only 2 powerful integers in this range.
7272

7373
<!-- solution:start -->
7474

75-
### Solution 1
75+
### Solution 1: Digit DP
76+
77+
This problem is essentially about finding the count of numbers in the given range $[l, .., r]$ that satisfy the conditions. The count depends on the number of digits and the value of each digit. We can solve this problem using the Digit DP approach, where the size of the number has minimal impact on the complexity.
78+
79+
For the range $[l, .., r]$, we typically transform it into two subproblems: $[1, .., r]$ and $[1, .., l - 1]$, i.e.,
80+
81+
$$
82+
ans = \sum_{i=1}^{r} ans_i - \sum_{i=1}^{l-1} ans_i
83+
$$
84+
85+
For this problem, we calculate the count of numbers in $[1, \textit{finish}]$ that satisfy the conditions, and subtract the count of numbers in $[1, \textit{start} - 1]$ that satisfy the conditions to get the final answer.
86+
87+
We use memoization to implement Digit DP. Starting from the topmost digit, we recursively calculate the number of valid numbers, accumulate the results layer by layer, and finally return the answer from the starting point.
88+
89+
The basic steps are as follows:
90+
91+
1. Convert $\textit{start}$ and $\textit{finish}$ to strings for easier manipulation in Digit DP.
92+
2. Design a function $\textit{dfs}(\textit{pos}, \textit{lim})$, which represents the count of valid numbers starting from the $\textit{pos}$-th digit, with the current restriction condition $\textit{lim}$.
93+
3. If the maximum number of digits is less than the length of $\textit{s}$, return 0.
94+
4. If the remaining number of digits equals the length of $\textit{s}$, check if the current number satisfies the condition and return 1 or 0.
95+
5. Otherwise, calculate the upper limit of the current digit as $\textit{up} = \min(\textit{lim} ? \textit{t}[\textit{pos}] : 9, \textit{limit})$. Then iterate through the digits $i$ from 0 to $\textit{up}$, recursively call $\textit{dfs}(\textit{pos} + 1, \textit{lim} \&\& i == \textit{t}[\textit{pos}])$, and accumulate the results.
96+
6. If $\textit{lim}$ is false, store the current result in the cache to avoid redundant calculations.
97+
7. Finally, return the result.
98+
99+
The answer is the count of valid numbers in $[1, \textit{finish}]$ minus the count of valid numbers in $[1, \textit{start} - 1]$.
100+
101+
Time complexity is $O(\log M \times D)$, and space complexity is $O(\log M)$, where $M$ is the upper limit of the number, and $D = 10$.
76102

77103
<!-- tabs:start -->
78104

@@ -82,7 +108,7 @@ It can be shown that there are only 2 powerful integers in this range.
82108
class Solution:
83109
def numberOfPowerfulInt(self, start: int, finish: int, limit: int, s: str) -> int:
84110
@cache
85-
def dfs(pos: int, lim: int):
111+
def dfs(pos: int, lim: int) -> int:
86112
if len(t) < n:
87113
return 0
88114
if len(t) - pos == n:
@@ -157,7 +183,7 @@ public:
157183
long long f[20];
158184
memset(f, -1, sizeof(f));
159185

160-
function<long long(int, bool)> dfs = [&](int pos, bool lim) -> long long {
186+
auto dfs = [&](this auto&& dfs, int pos, int lim) -> long long {
161187
if (t.size() < s.size()) {
162188
return 0;
163189
}
@@ -282,6 +308,51 @@ function numberOfPowerfulInt(start: number, finish: number, limit: number, s: st
282308
}
283309
```
284310

311+
#### C#
312+
313+
```cs
314+
public class Solution {
315+
private string s;
316+
private string t;
317+
private long?[] f;
318+
private int limit;
319+
320+
public long NumberOfPowerfulInt(long start, long finish, int limit, string s) {
321+
this.s = s;
322+
this.limit = limit;
323+
t = (start - 1).ToString();
324+
f = new long?[20];
325+
long a = Dfs(0, true);
326+
t = finish.ToString();
327+
f = new long?[20];
328+
long b = Dfs(0, true);
329+
return b - a;
330+
}
331+
332+
private long Dfs(int pos, bool lim) {
333+
if (t.Length < s.Length) {
334+
return 0;
335+
}
336+
if (!lim && f[pos].HasValue) {
337+
return f[pos].Value;
338+
}
339+
if (t.Length - pos == s.Length) {
340+
return lim ? (string.Compare(s, t.Substring(pos)) <= 0 ? 1 : 0) : 1;
341+
}
342+
int up = lim ? t[pos] - '0' : 9;
343+
up = Math.Min(up, limit);
344+
long ans = 0;
345+
for (int i = 0; i <= up; ++i) {
346+
ans += Dfs(pos + 1, lim && i == (t[pos] - '0'));
347+
}
348+
if (!lim) {
349+
f[pos] = ans;
350+
}
351+
return ans;
352+
}
353+
}
354+
```
355+
285356
<!-- tabs:end -->
286357

287358
<!-- solution:end -->

solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class Solution {
55
long long f[20];
66
memset(f, -1, sizeof(f));
77

8-
function<long long(int, bool)> dfs = [&](int pos, bool lim) -> long long {
8+
auto dfs = [&](this auto&& dfs, int pos, int lim) -> long long {
99
if (t.size() < s.size()) {
1010
return 0;
1111
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
public class Solution {
2+
private string s;
3+
private string t;
4+
private long?[] f;
5+
private int limit;
6+
7+
public long NumberOfPowerfulInt(long start, long finish, int limit, string s) {
8+
this.s = s;
9+
this.limit = limit;
10+
t = (start - 1).ToString();
11+
f = new long?[20];
12+
long a = Dfs(0, true);
13+
t = finish.ToString();
14+
f = new long?[20];
15+
long b = Dfs(0, true);
16+
return b - a;
17+
}
18+
19+
private long Dfs(int pos, bool lim) {
20+
if (t.Length < s.Length) {
21+
return 0;
22+
}
23+
if (!lim && f[pos].HasValue) {
24+
return f[pos].Value;
25+
}
26+
if (t.Length - pos == s.Length) {
27+
return lim ? (string.Compare(s, t.Substring(pos)) <= 0 ? 1 : 0) : 1;
28+
}
29+
int up = lim ? t[pos] - '0' : 9;
30+
up = Math.Min(up, limit);
31+
long ans = 0;
32+
for (int i = 0; i <= up; ++i) {
33+
ans += Dfs(pos + 1, lim && i == (t[pos] - '0'));
34+
}
35+
if (!lim) {
36+
f[pos] = ans;
37+
}
38+
return ans;
39+
}
40+
}

solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class Solution:
22
def numberOfPowerfulInt(self, start: int, finish: int, limit: int, s: str) -> int:
33
@cache
4-
def dfs(pos: int, lim: int):
4+
def dfs(pos: int, lim: int) -> int:
55
if len(t) < n:
66
return 0
77
if len(t) - pos == n:

0 commit comments

Comments
 (0)