diff --git a/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/README.md b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/README.md index adfdd1c42b25b..028941950b799 100644 --- a/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/README.md +++ b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/README.md @@ -61,32 +61,217 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3700-3799/3747.Co -### 方法一 +### 方法一:数位 DP + +题目实际上是要我们统计区间 $[1, n]$ 之间,数字中不含 0 的整数个数。我们可以使用数位 DP 来解决这个问题。 + +我们设计一个函数 $\text{dfs}(i, \text{zero}, \text{lead}, \text{limit})$,表示当前处理到数字的第 $i$ 位,用 $\text{zero}$ 表示当前数字中是否已经出现过非零数字,用 $\text{lead}$ 表示当前是否还在处理前导零,而 $\text{limit}$ 表示当前数字是否受上界限制的方案数。答案为 $\text{dfs}(0, 0, 1, 1)$。 + +函数 $\text{dfs}(i, \text{zero}, \text{lead}, \text{limit})$ 中,如果 $i$ 大于等于数字的长度,那么我们就可以判断 $\text{zero}$ 和 $\text{lead}$,如果 $\text{zero}$ 为假且 $\text{lead}$ 为假,说明当前数字中不含 0,我们就返回 $1$,否则返回 $0$。 + +对于 $\text{dfs}(i, \text{zero}, \text{lead}, \text{limit})$,我们可以枚举当前数位 $d$ 的值,然后递归计算 $\text{dfs}(i+1, \text{nxt\_zero}, \text{nxt\_lead}, \text{nxt\_limit})$,其中 $\text{nxt\_zero}$ 表示当前数字中是否已经出现过非零数字,$\text{nxt\_lead}$ 表示当前是否还在处理前导零,而 $\text{nxt\_limit}$ 表示当前数字是否受上界限制。如果 $\text{limit}$ 为真,那么 $up$ 就是当前数位的上界,否则 $up$ 为 $9$。 + +时间复杂度 $O(\log_{10} n \times D)$,空间复杂度 $O(\log_{10} n)$。其中 $D$ 表示数字 0 到 9 的个数。 #### Python3 ```python - +class Solution: + def countDistinct(self, n: int) -> int: + @cache + def dfs(i: int, zero: bool, lead: bool, lim: bool) -> int: + if i >= len(s): + return 1 if (not zero and not lead) else 0 + up = int(s[i]) if lim else 9 + ans = 0 + for j in range(up + 1): + nxt_zero = zero or (j == 0 and not lead) + nxt_lead = lead and j == 0 + nxt_lim = lim and j == up + ans += dfs(i + 1, nxt_zero, nxt_lead, nxt_lim) + return ans + + s = str(n) + return dfs(0, False, True, True) ``` #### Java ```java - +class Solution { + private char[] s; + private Long[][][][] f; + + public long countDistinct(long n) { + s = String.valueOf(n).toCharArray(); + f = new Long[s.length][2][2][2]; + return dfs(0, 0, 1, 1); + } + + private long dfs(int i, int zero, int lead, int limit) { + if (i == s.length) { + return (zero == 0 && lead == 0) ? 1 : 0; + } + + if (limit == 0 && f[i][zero][lead][limit] != null) { + return f[i][zero][lead][limit]; + } + + int up = limit == 1 ? s[i] - '0' : 9; + long ans = 0; + for (int d = 0; d <= up; d++) { + int nxtZero = zero == 1 || (d == 0 && lead == 0) ? 1 : 0; + int nxtLead = (lead == 1 && d == 0) ? 1 : 0; + int nxtLimit = (limit == 1 && d == up) ? 1 : 0; + ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit); + } + + if (limit == 0) { + f[i][zero][lead][limit] = ans; + } + return ans; + } +} ``` #### C++ ```cpp - +class Solution { +public: + long long countDistinct(long long n) { + string s = to_string(n); + int m = s.size(); + static long long f[20][2][2][2]; + memset(f, -1, sizeof(f)); + + auto dfs = [&](this auto&& dfs, int i, int zero, int lead, int limit) -> long long { + if (i == m) { + return (zero == 0 && lead == 0) ? 1 : 0; + } + if (!limit && f[i][zero][lead][limit] != -1) { + return f[i][zero][lead][limit]; + } + + int up = limit ? (s[i] - '0') : 9; + long long ans = 0; + for (int d = 0; d <= up; d++) { + int nxtZero = zero || (d == 0 && !lead); + int nxtLead = lead && d == 0; + int nxtLimit = limit && d == up; + ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit); + } + + if (!limit) f[i][zero][lead][limit] = ans; + return ans; + }; + + return dfs(0, 0, 1, 1); + } +}; ``` #### Go ```go +func countDistinct(n int64) int64 { + s := []byte(fmt.Sprint(n)) + m := len(s) + var f [20][2][2][2]int64 + for i := range f { + for j := range f[i] { + for k := range f[i][j] { + for t := range f[i][j][k] { + f[i][j][k][t] = -1 + } + } + } + } + + var dfs func(i, zero, lead, limit int) int64 + dfs = func(i, zero, lead, limit int) int64 { + if i == m { + if zero == 0 && lead == 0 { + return 1 + } + return 0 + } + + if limit == 0 && f[i][zero][lead][limit] != -1 { + return f[i][zero][lead][limit] + } + + up := 9 + if limit == 1 { + up = int(s[i] - '0') + } + + var ans int64 = 0 + for d := 0; d <= up; d++ { + nxtZero := zero + if d == 0 && lead == 0 { + nxtZero = 1 + } + nxtLead := 0 + if lead == 1 && d == 0 { + nxtLead = 1 + } + nxtLimit := 0 + if limit == 1 && d == up { + nxtLimit = 1 + } + ans += dfs(i+1, nxtZero, nxtLead, nxtLimit) + } + + if limit == 0 { + f[i][zero][lead][limit] = ans + } + return ans + } + + return dfs(0, 0, 1, 1) +} +``` +#### TypeScript + +```ts +function countDistinct(n: number): number { + const s = n.toString(); + const m = s.length; + + const f: number[][][][] = Array.from({ length: m }, () => + Array.from({ length: 2 }, () => Array.from({ length: 2 }, () => Array(2).fill(-1))), + ); + + const dfs = (i: number, zero: number, lead: number, limit: number): number => { + if (i === m) { + return zero === 0 && lead === 0 ? 1 : 0; + } + + if (limit === 0 && f[i][zero][lead][limit] !== -1) { + return f[i][zero][lead][limit]; + } + + const up = limit === 1 ? parseInt(s[i]) : 9; + let ans = 0; + for (let d = 0; d <= up; d++) { + const nxtZero = zero === 1 || (d === 0 && lead === 0) ? 1 : 0; + const nxtLead = lead === 1 && d === 0 ? 1 : 0; + const nxtLimit = limit === 1 && d === up ? 1 : 0; + ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit); + } + + if (limit === 0) { + f[i][zero][lead][limit] = ans; + } + return ans; + }; + + return dfs(0, 0, 1, 1); +} ``` diff --git a/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/README_EN.md b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/README_EN.md index b570691586584..80fe07cba5cf4 100644 --- a/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/README_EN.md +++ b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/README_EN.md @@ -58,32 +58,217 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3700-3799/3747.Co -### Solution 1 +### Solution 1: Digit DP + +The problem essentially asks us to count the number of integers in the range $[1, n]$ that do not contain the digit 0. We can solve this problem using digit DP. + +We design a function $\text{dfs}(i, \text{zero}, \text{lead}, \text{limit})$, which represents the number of valid solutions when we are currently processing the $i$-th digit of the number. We use $\text{zero}$ to indicate whether a non-zero digit has appeared in the current number, $\text{lead}$ to indicate whether we are still processing leading zeros, and $\text{limit}$ to indicate whether the current number is constrained by the upper bound. The answer is $\text{dfs}(0, 0, 1, 1)$. + +In the function $\text{dfs}(i, \text{zero}, \text{lead}, \text{limit})$, if $i$ is greater than or equal to the length of the number, we can check $\text{zero}$ and $\text{lead}$. If $\text{zero}$ is false and $\text{lead}$ is false, it means the current number does not contain 0, so we return $1$; otherwise, we return $0$. + +For $\text{dfs}(i, \text{zero}, \text{lead}, \text{limit})$, we can enumerate the value of the current digit $d$, then recursively calculate $\text{dfs}(i+1, \text{nxt\_zero}, \text{nxt\_lead}, \text{nxt\_limit})$, where $\text{nxt\_zero}$ indicates whether a non-zero digit has appeared in the current number, $\text{nxt\_lead}$ indicates whether we are still processing leading zeros, and $\text{nxt\_limit}$ indicates whether the current number is constrained by the upper bound. If $\text{limit}$ is true, then $up$ is the upper bound of the current digit; otherwise, $up$ is $9$. + +The time complexity is $O(\log_{10} n \times D)$ and the space complexity is $O(\log_{10} n)$, where $D$ represents the count of digits from 0 to 9. #### Python3 ```python - +class Solution: + def countDistinct(self, n: int) -> int: + @cache + def dfs(i: int, zero: bool, lead: bool, lim: bool) -> int: + if i >= len(s): + return 1 if (not zero and not lead) else 0 + up = int(s[i]) if lim else 9 + ans = 0 + for j in range(up + 1): + nxt_zero = zero or (j == 0 and not lead) + nxt_lead = lead and j == 0 + nxt_lim = lim and j == up + ans += dfs(i + 1, nxt_zero, nxt_lead, nxt_lim) + return ans + + s = str(n) + return dfs(0, False, True, True) ``` #### Java ```java - +class Solution { + private char[] s; + private Long[][][][] f; + + public long countDistinct(long n) { + s = String.valueOf(n).toCharArray(); + f = new Long[s.length][2][2][2]; + return dfs(0, 0, 1, 1); + } + + private long dfs(int i, int zero, int lead, int limit) { + if (i == s.length) { + return (zero == 0 && lead == 0) ? 1 : 0; + } + + if (limit == 0 && f[i][zero][lead][limit] != null) { + return f[i][zero][lead][limit]; + } + + int up = limit == 1 ? s[i] - '0' : 9; + long ans = 0; + for (int d = 0; d <= up; d++) { + int nxtZero = zero == 1 || (d == 0 && lead == 0) ? 1 : 0; + int nxtLead = (lead == 1 && d == 0) ? 1 : 0; + int nxtLimit = (limit == 1 && d == up) ? 1 : 0; + ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit); + } + + if (limit == 0) { + f[i][zero][lead][limit] = ans; + } + return ans; + } +} ``` #### C++ ```cpp - +class Solution { +public: + long long countDistinct(long long n) { + string s = to_string(n); + int m = s.size(); + static long long f[20][2][2][2]; + memset(f, -1, sizeof(f)); + + auto dfs = [&](this auto&& dfs, int i, int zero, int lead, int limit) -> long long { + if (i == m) { + return (zero == 0 && lead == 0) ? 1 : 0; + } + if (!limit && f[i][zero][lead][limit] != -1) { + return f[i][zero][lead][limit]; + } + + int up = limit ? (s[i] - '0') : 9; + long long ans = 0; + for (int d = 0; d <= up; d++) { + int nxtZero = zero || (d == 0 && !lead); + int nxtLead = lead && d == 0; + int nxtLimit = limit && d == up; + ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit); + } + + if (!limit) f[i][zero][lead][limit] = ans; + return ans; + }; + + return dfs(0, 0, 1, 1); + } +}; ``` #### Go ```go +func countDistinct(n int64) int64 { + s := []byte(fmt.Sprint(n)) + m := len(s) + var f [20][2][2][2]int64 + for i := range f { + for j := range f[i] { + for k := range f[i][j] { + for t := range f[i][j][k] { + f[i][j][k][t] = -1 + } + } + } + } + + var dfs func(i, zero, lead, limit int) int64 + dfs = func(i, zero, lead, limit int) int64 { + if i == m { + if zero == 0 && lead == 0 { + return 1 + } + return 0 + } + + if limit == 0 && f[i][zero][lead][limit] != -1 { + return f[i][zero][lead][limit] + } + + up := 9 + if limit == 1 { + up = int(s[i] - '0') + } + + var ans int64 = 0 + for d := 0; d <= up; d++ { + nxtZero := zero + if d == 0 && lead == 0 { + nxtZero = 1 + } + nxtLead := 0 + if lead == 1 && d == 0 { + nxtLead = 1 + } + nxtLimit := 0 + if limit == 1 && d == up { + nxtLimit = 1 + } + ans += dfs(i+1, nxtZero, nxtLead, nxtLimit) + } + + if limit == 0 { + f[i][zero][lead][limit] = ans + } + return ans + } + + return dfs(0, 0, 1, 1) +} +``` +#### TypeScript + +```ts +function countDistinct(n: number): number { + const s = n.toString(); + const m = s.length; + + const f: number[][][][] = Array.from({ length: m }, () => + Array.from({ length: 2 }, () => Array.from({ length: 2 }, () => Array(2).fill(-1))), + ); + + const dfs = (i: number, zero: number, lead: number, limit: number): number => { + if (i === m) { + return zero === 0 && lead === 0 ? 1 : 0; + } + + if (limit === 0 && f[i][zero][lead][limit] !== -1) { + return f[i][zero][lead][limit]; + } + + const up = limit === 1 ? parseInt(s[i]) : 9; + let ans = 0; + for (let d = 0; d <= up; d++) { + const nxtZero = zero === 1 || (d === 0 && lead === 0) ? 1 : 0; + const nxtLead = lead === 1 && d === 0 ? 1 : 0; + const nxtLimit = limit === 1 && d === up ? 1 : 0; + ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit); + } + + if (limit === 0) { + f[i][zero][lead][limit] = ans; + } + return ans; + }; + + return dfs(0, 0, 1, 1); +} ``` diff --git a/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.cpp b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.cpp new file mode 100644 index 0000000000000..6c6d3f9b2be3a --- /dev/null +++ b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.cpp @@ -0,0 +1,32 @@ +class Solution { +public: + long long countDistinct(long long n) { + string s = to_string(n); + int m = s.size(); + static long long f[20][2][2][2]; + memset(f, -1, sizeof(f)); + + auto dfs = [&](this auto&& dfs, int i, int zero, int lead, int limit) -> long long { + if (i == m) { + return (zero == 0 && lead == 0) ? 1 : 0; + } + if (!limit && f[i][zero][lead][limit] != -1) { + return f[i][zero][lead][limit]; + } + + int up = limit ? (s[i] - '0') : 9; + long long ans = 0; + for (int d = 0; d <= up; d++) { + int nxtZero = zero || (d == 0 && !lead); + int nxtLead = lead && d == 0; + int nxtLimit = limit && d == up; + ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit); + } + + if (!limit) f[i][zero][lead][limit] = ans; + return ans; + }; + + return dfs(0, 0, 1, 1); + } +}; diff --git a/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.go b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.go new file mode 100644 index 0000000000000..37b7d78b19e3d --- /dev/null +++ b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.go @@ -0,0 +1,57 @@ +func countDistinct(n int64) int64 { + s := []byte(fmt.Sprint(n)) + m := len(s) + var f [20][2][2][2]int64 + for i := range f { + for j := range f[i] { + for k := range f[i][j] { + for t := range f[i][j][k] { + f[i][j][k][t] = -1 + } + } + } + } + + var dfs func(i, zero, lead, limit int) int64 + dfs = func(i, zero, lead, limit int) int64 { + if i == m { + if zero == 0 && lead == 0 { + return 1 + } + return 0 + } + + if limit == 0 && f[i][zero][lead][limit] != -1 { + return f[i][zero][lead][limit] + } + + up := 9 + if limit == 1 { + up = int(s[i] - '0') + } + + var ans int64 = 0 + for d := 0; d <= up; d++ { + nxtZero := zero + if d == 0 && lead == 0 { + nxtZero = 1 + } + nxtLead := 0 + if lead == 1 && d == 0 { + nxtLead = 1 + } + nxtLimit := 0 + if limit == 1 && d == up { + nxtLimit = 1 + } + ans += dfs(i+1, nxtZero, nxtLead, nxtLimit) + } + + if limit == 0 { + f[i][zero][lead][limit] = ans + } + return ans + } + + return dfs(0, 0, 1, 1) +} diff --git a/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.java b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.java new file mode 100644 index 0000000000000..18a5a069819fb --- /dev/null +++ b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.java @@ -0,0 +1,34 @@ +class Solution { + private char[] s; + private Long[][][][] f; + + public long countDistinct(long n) { + s = String.valueOf(n).toCharArray(); + f = new Long[s.length][2][2][2]; + return dfs(0, 0, 1, 1); + } + + private long dfs(int i, int zero, int lead, int limit) { + if (i == s.length) { + return (zero == 0 && lead == 0) ? 1 : 0; + } + + if (limit == 0 && f[i][zero][lead][limit] != null) { + return f[i][zero][lead][limit]; + } + + int up = limit == 1 ? s[i] - '0' : 9; + long ans = 0; + for (int d = 0; d <= up; d++) { + int nxtZero = zero == 1 || (d == 0 && lead == 0) ? 1 : 0; + int nxtLead = (lead == 1 && d == 0) ? 1 : 0; + int nxtLimit = (limit == 1 && d == up) ? 1 : 0; + ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit); + } + + if (limit == 0) { + f[i][zero][lead][limit] = ans; + } + return ans; + } +} diff --git a/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.py b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.py new file mode 100644 index 0000000000000..8c5d94d15b05d --- /dev/null +++ b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.py @@ -0,0 +1,17 @@ +class Solution: + def countDistinct(self, n: int) -> int: + @cache + def dfs(i: int, zero: bool, lead: bool, lim: bool) -> int: + if i >= len(s): + return 1 if (not zero and not lead) else 0 + up = int(s[i]) if lim else 9 + ans = 0 + for j in range(up + 1): + nxt_zero = zero or (j == 0 and not lead) + nxt_lead = lead and j == 0 + nxt_lim = lim and j == up + ans += dfs(i + 1, nxt_zero, nxt_lead, nxt_lim) + return ans + + s = str(n) + return dfs(0, False, True, True) diff --git a/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.ts b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.ts new file mode 100644 index 0000000000000..bf07b1fdb2876 --- /dev/null +++ b/solution/3700-3799/3747.Count Distinct Integers After Removing Zeros/Solution.ts @@ -0,0 +1,34 @@ +function countDistinct(n: number): number { + const s = n.toString(); + const m = s.length; + + const f: number[][][][] = Array.from({ length: m }, () => + Array.from({ length: 2 }, () => Array.from({ length: 2 }, () => Array(2).fill(-1))), + ); + + const dfs = (i: number, zero: number, lead: number, limit: number): number => { + if (i === m) { + return zero === 0 && lead === 0 ? 1 : 0; + } + + if (limit === 0 && f[i][zero][lead][limit] !== -1) { + return f[i][zero][lead][limit]; + } + + const up = limit === 1 ? parseInt(s[i]) : 9; + let ans = 0; + for (let d = 0; d <= up; d++) { + const nxtZero = zero === 1 || (d === 0 && lead === 0) ? 1 : 0; + const nxtLead = lead === 1 && d === 0 ? 1 : 0; + const nxtLimit = limit === 1 && d === up ? 1 : 0; + ans += dfs(i + 1, nxtZero, nxtLead, nxtLimit); + } + + if (limit === 0) { + f[i][zero][lead][limit] = ans; + } + return ans; + }; + + return dfs(0, 0, 1, 1); +}