From 55b91a12e8f0f8c6ae1239906941c58789e4b091 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Tue, 1 Apr 2025 21:43:50 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.2999 --- .../README.md | 77 ++++++++++++++++++- .../README_EN.md | 77 ++++++++++++++++++- .../Solution.cpp | 2 +- .../Solution.cs | 40 ++++++++++ .../Solution.py | 2 +- 5 files changed, 190 insertions(+), 8 deletions(-) create mode 100644 solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.cs diff --git a/solution/2900-2999/2999.Count the Number of Powerful Integers/README.md b/solution/2900-2999/2999.Count the Number of Powerful Integers/README.md index 6537a1be36b84..cec5a5d000ce6 100644 --- a/solution/2900-2999/2999.Count the Number of Powerful Integers/README.md +++ b/solution/2900-2999/2999.Count the Number of Powerful Integers/README.md @@ -74,7 +74,33 @@ tags: -### 方法一 +### 方法一:数位 DP + +这道题实际上是求在给定区间 $[l,..r]$ 中,满足条件的数的个数。个数与数的位数以及每一位上的数字有关。我们可以用数位 DP 的思路来解决这道题。数位 DP 中,数的大小对复杂度的影响很小。 + +对于区间 $[l,..r]$ 问题,我们一般会将其转化为 $[1,..r]$ 然后再减去 $[1,..l - 1]$ 的问题,即: + +$$ +ans = \sum_{i=1}^{r} ans_i - \sum_{i=1}^{l-1} ans_i +$$ + +对于本题而言,我们求出 $[1, \textit{finish}]$ 中满足条件的数的个数,然后减去 $[1, \textit{start} - 1]$ 中满足条件的数的个数,即可得到答案。 + +这里我们用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。 + +基本步骤如下: + +1. 先将 $\textit{start}$ 和 $\textit{finish}$ 转化为字符串,方便后续的数位 DP。 +2. 设计一个函数 $\textit{dfs}(\textit{pos}, \textit{lim})$,表示从第 $\textit{pos}$ 位开始搜索,当前的限制条件为 $\textit{lim}$。 +3. 如果最大的数字位数小于 $\textit{s}$ 的长度,返回 0。 +4. 如果当前剩余的数字位数等于 $\textit{s}$ 的长度,判断当前的数字是否满足条件,返回 1 或 0。 +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}])$,将结果累加到答案中。 +6. 如果当前的 $\textit{lim}$ 为 false,则将当前的答案存入缓存中,避免重复计算。 +7. 最后返回答案。 + +答案为区间 $[1, \textit{finish}]$ 中满足条件的数的个数减去区间 $[1, \textit{start} - 1]$ 中满足条件的数的个数。 + +时间复杂度 $O(\log M \times D)$,空间复杂度 $O(\log M)$,其中 $M$ 为数字的上限,而 $D = 10$。 @@ -84,7 +110,7 @@ tags: class Solution: def numberOfPowerfulInt(self, start: int, finish: int, limit: int, s: str) -> int: @cache - def dfs(pos: int, lim: int): + def dfs(pos: int, lim: int) -> int: if len(t) < n: return 0 if len(t) - pos == n: @@ -159,7 +185,7 @@ public: long long f[20]; memset(f, -1, sizeof(f)); - function dfs = [&](int pos, bool lim) -> long long { + auto dfs = [&](this auto&& dfs, int pos, int lim) -> long long { if (t.size() < s.size()) { return 0; } @@ -284,6 +310,51 @@ function numberOfPowerfulInt(start: number, finish: number, limit: number, s: st } ``` +#### C# + +```cs +public class Solution { + private string s; + private string t; + private long?[] f; + private int limit; + + public long NumberOfPowerfulInt(long start, long finish, int limit, string s) { + this.s = s; + this.limit = limit; + t = (start - 1).ToString(); + f = new long?[20]; + long a = Dfs(0, true); + t = finish.ToString(); + f = new long?[20]; + long b = Dfs(0, true); + return b - a; + } + + private long Dfs(int pos, bool lim) { + if (t.Length < s.Length) { + return 0; + } + if (!lim && f[pos].HasValue) { + return f[pos].Value; + } + if (t.Length - pos == s.Length) { + return lim ? (string.Compare(s, t.Substring(pos)) <= 0 ? 1 : 0) : 1; + } + int up = lim ? t[pos] - '0' : 9; + up = Math.Min(up, limit); + long ans = 0; + for (int i = 0; i <= up; ++i) { + ans += Dfs(pos + 1, lim && i == (t[pos] - '0')); + } + if (!lim) { + f[pos] = ans; + } + return ans; + } +} +``` + diff --git a/solution/2900-2999/2999.Count the Number of Powerful Integers/README_EN.md b/solution/2900-2999/2999.Count the Number of Powerful Integers/README_EN.md index 2b975af6910dc..5ffa6ef4c116e 100644 --- a/solution/2900-2999/2999.Count the Number of Powerful Integers/README_EN.md +++ b/solution/2900-2999/2999.Count the Number of Powerful Integers/README_EN.md @@ -72,7 +72,33 @@ It can be shown that there are only 2 powerful integers in this range. -### Solution 1 +### Solution 1: Digit DP + +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. + +For the range $[l, .., r]$, we typically transform it into two subproblems: $[1, .., r]$ and $[1, .., l - 1]$, i.e., + +$$ +ans = \sum_{i=1}^{r} ans_i - \sum_{i=1}^{l-1} ans_i +$$ + +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. + +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. + +The basic steps are as follows: + +1. Convert $\textit{start}$ and $\textit{finish}$ to strings for easier manipulation in Digit DP. +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}$. +3. If the maximum number of digits is less than the length of $\textit{s}$, return 0. +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. +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. +6. If $\textit{lim}$ is false, store the current result in the cache to avoid redundant calculations. +7. Finally, return the result. + +The answer is the count of valid numbers in $[1, \textit{finish}]$ minus the count of valid numbers in $[1, \textit{start} - 1]$. + +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$. @@ -82,7 +108,7 @@ It can be shown that there are only 2 powerful integers in this range. class Solution: def numberOfPowerfulInt(self, start: int, finish: int, limit: int, s: str) -> int: @cache - def dfs(pos: int, lim: int): + def dfs(pos: int, lim: int) -> int: if len(t) < n: return 0 if len(t) - pos == n: @@ -157,7 +183,7 @@ public: long long f[20]; memset(f, -1, sizeof(f)); - function dfs = [&](int pos, bool lim) -> long long { + auto dfs = [&](this auto&& dfs, int pos, int lim) -> long long { if (t.size() < s.size()) { return 0; } @@ -282,6 +308,51 @@ function numberOfPowerfulInt(start: number, finish: number, limit: number, s: st } ``` +#### C# + +```cs +public class Solution { + private string s; + private string t; + private long?[] f; + private int limit; + + public long NumberOfPowerfulInt(long start, long finish, int limit, string s) { + this.s = s; + this.limit = limit; + t = (start - 1).ToString(); + f = new long?[20]; + long a = Dfs(0, true); + t = finish.ToString(); + f = new long?[20]; + long b = Dfs(0, true); + return b - a; + } + + private long Dfs(int pos, bool lim) { + if (t.Length < s.Length) { + return 0; + } + if (!lim && f[pos].HasValue) { + return f[pos].Value; + } + if (t.Length - pos == s.Length) { + return lim ? (string.Compare(s, t.Substring(pos)) <= 0 ? 1 : 0) : 1; + } + int up = lim ? t[pos] - '0' : 9; + up = Math.Min(up, limit); + long ans = 0; + for (int i = 0; i <= up; ++i) { + ans += Dfs(pos + 1, lim && i == (t[pos] - '0')); + } + if (!lim) { + f[pos] = ans; + } + return ans; + } +} +``` + diff --git a/solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.cpp b/solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.cpp index dc348ec436cb0..df98ac39b5fd6 100644 --- a/solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.cpp +++ b/solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.cpp @@ -5,7 +5,7 @@ class Solution { long long f[20]; memset(f, -1, sizeof(f)); - function dfs = [&](int pos, bool lim) -> long long { + auto dfs = [&](this auto&& dfs, int pos, int lim) -> long long { if (t.size() < s.size()) { return 0; } diff --git a/solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.cs b/solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.cs new file mode 100644 index 0000000000000..8b637cef8f8d6 --- /dev/null +++ b/solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.cs @@ -0,0 +1,40 @@ +public class Solution { + private string s; + private string t; + private long?[] f; + private int limit; + + public long NumberOfPowerfulInt(long start, long finish, int limit, string s) { + this.s = s; + this.limit = limit; + t = (start - 1).ToString(); + f = new long?[20]; + long a = Dfs(0, true); + t = finish.ToString(); + f = new long?[20]; + long b = Dfs(0, true); + return b - a; + } + + private long Dfs(int pos, bool lim) { + if (t.Length < s.Length) { + return 0; + } + if (!lim && f[pos].HasValue) { + return f[pos].Value; + } + if (t.Length - pos == s.Length) { + return lim ? (string.Compare(s, t.Substring(pos)) <= 0 ? 1 : 0) : 1; + } + int up = lim ? t[pos] - '0' : 9; + up = Math.Min(up, limit); + long ans = 0; + for (int i = 0; i <= up; ++i) { + ans += Dfs(pos + 1, lim && i == (t[pos] - '0')); + } + if (!lim) { + f[pos] = ans; + } + return ans; + } +} \ No newline at end of file diff --git a/solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.py b/solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.py index 6929287609761..3fab31670bb2e 100644 --- a/solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.py +++ b/solution/2900-2999/2999.Count the Number of Powerful Integers/Solution.py @@ -1,7 +1,7 @@ class Solution: def numberOfPowerfulInt(self, start: int, finish: int, limit: int, s: str) -> int: @cache - def dfs(pos: int, lim: int): + def dfs(pos: int, lim: int) -> int: if len(t) < n: return 0 if len(t) - pos == n: