From 92b341ddd673ab82708bd6ce693257a954d7a3df Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 20 Sep 2024 17:28:11 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.0788 No.0788.Rotated Digits --- .../0700-0799/0788.Rotated Digits/README.md | 271 +++++++++------- .../0788.Rotated Digits/README_EN.md | 305 +++++++++++------- .../0788.Rotated Digits/Solution.cpp | 34 +- .../0700-0799/0788.Rotated Digits/Solution.ts | 20 ++ .../0788.Rotated Digits/Solution2.cpp | 57 ++-- .../0788.Rotated Digits/Solution2.go | 46 ++- .../0788.Rotated Digits/Solution2.java | 41 +-- .../0788.Rotated Digits/Solution2.py | 25 +- .../0788.Rotated Digits/Solution2.ts | 27 ++ 9 files changed, 475 insertions(+), 351 deletions(-) create mode 100644 solution/0700-0799/0788.Rotated Digits/Solution.ts create mode 100644 solution/0700-0799/0788.Rotated Digits/Solution2.ts diff --git a/solution/0700-0799/0788.Rotated Digits/README.md b/solution/0700-0799/0788.Rotated Digits/README.md index a5b0b24187718..5299736cd7e98 100644 --- a/solution/0700-0799/0788.Rotated Digits/README.md +++ b/solution/0700-0799/0788.Rotated Digits/README.md @@ -29,7 +29,7 @@ tags:
输入: 10
 输出: 4
-解释: 
+解释:
 在[1, 10]中有四个好数: 2, 5, 6, 9。
 注意 1 和 10 不是好数, 因为他们在旋转之后不变。
 
@@ -56,9 +56,9 @@ tags: 我们先用一个长度为 $10$ 的数组 $d$ 记录每个有效数字对应的旋转数字,在这道题中,有效数字有 $[0, 1, 8, 2, 5, 6, 9]$,分别对应旋转数字 $[0, 1, 8, 5, 2, 9, 6]$。如果不是有效数字,我们将对应的旋转数字设为 $-1$。 -然后遍历数字 $x$ 的每一位数字 $v$,如果 $v$ 不是有效数字,说明 $x$ 不是好数,直接返回 `false`。否则,我们将数字 $v$ 对应的旋转数字 $d[v]$ 加入到 $y$ 中。最后,判断 $x$ 和 $y$ 是否相等,若不相等,则说明 $x$ 是好数,返回 `true`。 +然后遍历数字 $x$ 的每一位数字 $v$,如果 $v$ 不是有效数字,说明 $x$ 不是好数,直接返回 $\textit{false}$。否则,我们将数字 $v$ 对应的旋转数字 $d[v]$ 加入到 $y$ 中。最后,判断 $x$ 和 $y$ 是否相等,若不相等,则说明 $x$ 是好数,返回 $\textit{true}$。 -时间复杂度 $O(n\times \log n)$。 +时间复杂度 $O(n \times \log n)$,其中 $n$ 为题目给定的数字。空间复杂度 $O(1)$。 相似题目: @@ -125,30 +125,28 @@ class Solution { ```cpp class Solution { public: - const vector d = {0, 1, 5, -1, -1, 2, 9, -1, 8, 6}; - int rotatedDigits(int n) { + int d[10] = {0, 1, 5, -1, -1, 2, 9, -1, 8, 6}; + auto check = [&](int x) -> bool { + int y = 0, t = x; + int k = 1; + while (t) { + int v = t % 10; + if (d[v] == -1) { + return false; + } + y = d[v] * k + y; + k *= 10; + t /= 10; + } + return x != y; + }; int ans = 0; for (int i = 1; i <= n; ++i) { ans += check(i); } return ans; } - - bool check(int x) { - int y = 0, t = x; - int k = 1; - while (t) { - int v = t % 10; - if (d[v] == -1) { - return false; - } - y = d[v] * k + y; - k *= 10; - t /= 10; - } - return x != y; - } }; ``` @@ -180,6 +178,31 @@ func rotatedDigits(n int) int { } ``` +#### TypeScript + +```ts +function rotatedDigits(n: number): number { + const d: number[] = [0, 1, 5, -1, -1, 2, 9, -1, 8, 6]; + const check = (x: number): boolean => { + let y = 0; + let t = x; + let k = 1; + + while (t > 0) { + const v = t % 10; + if (d[v] === -1) { + return false; + } + y = d[v] * k + y; + k *= 10; + t = Math.floor(t / 10); + } + return x !== y; + }; + return Array.from({ length: n }, (_, i) => i + 1).filter(check).length; +} +``` + @@ -204,18 +227,17 @@ $$ 基本步骤如下: -1. 将数字 $n$ 转为 int 数组 $a$,其中 $a[1]$ 为最低位,而 $a[len]$ 为最高位; -1. 根据题目信息,设计函数 $dfs()$,对于本题,我们定义 $dfs(pos, ok, limit)$,答案为 $dfs(len, 0, true)$。 +我们将数字 $n$ 转为字符串 $s$。然后定义函数 $\textit{dfs}(i, \textit{ok}, \textit{limit})$,其中 $i$ 表示数字的位数,数字 $\textit{ok}$ 表示当前数字是否满足题目要求,布尔值 $\textit{limit}$ 表示可填的数字的限制。 -其中: +函数的执行逻辑如下: -- `pos` 表示数字的位数,从末位或者第一位开始,一般根据题目的数字构造性质来选择顺序。对于本题,我们选择从高位开始,因此,`pos` 的初始值为 `len`; -- `ok` 表示当前数字是否满足题目要求(对于本题,如果数字出现 $[2, 5, 6, 9]$ 则满足) -- `limit` 表示可填的数字的限制,如果无限制,那么可以选择 $[0,1,..9]$,否则,只能选择 $[0,..a[pos]]$。如果 `limit` 为 `true` 且已经取到了能取到的最大值,那么下一个 `limit` 同样为 `true`;如果 `limit` 为 `true` 但是还没有取到最大值,或者 `limit` 为 `false`,那么下一个 `limit` 为 `false`。 +如果 $i$ 大于等于字符串 $s$ 的长度,返回 $\textit{ok}$; -关于函数的实现细节,可以参考下面的代码。 +否则,我们获取当前位的数字 $up$,如果 $\textit{limit}$ 为 $\textit{true}$,则 $up$ 为当前位的数字,否则 $up$ 为 $9$; -时间复杂度 $O(\log n)$。 +接下来,我们遍历 $[0,..up]$,如果 $j$ 是有效数字 $[0, 1, 8]$,则递归调用 $\textit{dfs}(i + 1, \textit{ok}, \textit{limit} \land j = \textit{up})$;如果 $j$ 是有效数字 $[2, 5, 6, 9]$,则递归调用 $\textit{dfs}(i + 1, 1, \textit{limit} \land j = \textit{up})$;将所有递归调用的结果累加并返回。 + +时间复杂度 $O(\log n \times D)$,空间复杂度 $O(\log n)$。其中 $D = 10$。 相似题目: @@ -234,65 +256,53 @@ $$ class Solution: def rotatedDigits(self, n: int) -> int: @cache - def dfs(pos, ok, limit): - if pos <= 0: + def dfs(i: int, ok: int, limit: bool) -> int: + if i >= len(s): return ok - up = a[pos] if limit else 9 + up = int(s[i]) if limit else 9 ans = 0 - for i in range(up + 1): - if i in (0, 1, 8): - ans += dfs(pos - 1, ok, limit and i == up) - if i in (2, 5, 6, 9): - ans += dfs(pos - 1, 1, limit and i == up) + for j in range(up + 1): + if j in (0, 1, 8): + ans += dfs(i + 1, ok, limit and j == up) + elif j in (2, 5, 6, 9): + ans += dfs(i + 1, 1, limit and j == up) return ans - a = [0] * 6 - l = 1 - while n: - a[l] = n % 10 - n //= 10 - l += 1 - return dfs(l, 0, True) + s = str(n) + return dfs(0, 0, True) ``` #### Java ```java class Solution { - private int[] a = new int[6]; - private int[][] dp = new int[6][2]; + private char[] s; + private Integer[][] f; public int rotatedDigits(int n) { - int len = 0; - for (var e : dp) { - Arrays.fill(e, -1); - } - while (n > 0) { - a[++len] = n % 10; - n /= 10; - } - return dfs(len, 0, true); + s = String.valueOf(n).toCharArray(); + f = new Integer[s.length][2]; + return dfs(0, 0, true); } - private int dfs(int pos, int ok, boolean limit) { - if (pos <= 0) { + private int dfs(int i, int ok, boolean limit) { + if (i >= s.length) { return ok; } - if (!limit && dp[pos][ok] != -1) { - return dp[pos][ok]; + if (!limit && f[i][ok] != null) { + return f[i][ok]; } - int up = limit ? a[pos] : 9; + int up = limit ? s[i] - '0' : 9; int ans = 0; - for (int i = 0; i <= up; ++i) { - if (i == 0 || i == 1 || i == 8) { - ans += dfs(pos - 1, ok, limit && i == up); - } - if (i == 2 || i == 5 || i == 6 || i == 9) { - ans += dfs(pos - 1, 1, limit && i == up); + for (int j = 0; j <= up; ++j) { + if (j == 0 || j == 1 || j == 8) { + ans += dfs(i + 1, ok, limit && j == up); + } else if (j == 2 || j == 5 || j == 6 || j == 9) { + ans += dfs(i + 1, 1, limit && j == up); } } if (!limit) { - dp[pos][ok] = ans; + f[i][ok] = ans; } return ans; } @@ -304,40 +314,33 @@ class Solution { ```cpp class Solution { public: - int a[6]; - int dp[6][2]; - int rotatedDigits(int n) { - memset(dp, -1, sizeof dp); - int len = 0; - while (n) { - a[++len] = n % 10; - n /= 10; - } - return dfs(len, 0, true); - } - - int dfs(int pos, int ok, bool limit) { - if (pos <= 0) { - return ok; - } - if (!limit && dp[pos][ok] != -1) { - return dp[pos][ok]; - } - int up = limit ? a[pos] : 9; - int ans = 0; - for (int i = 0; i <= up; ++i) { - if (i == 0 || i == 1 || i == 8) { - ans += dfs(pos - 1, ok, limit && i == up); + string s = to_string(n); + int m = s.size(); + int f[m][2]; + memset(f, -1, sizeof(f)); + auto dfs = [&](auto&& dfs, int i, int ok, bool limit) -> int { + if (i >= m) { + return ok; } - if (i == 2 || i == 5 || i == 6 || i == 9) { - ans += dfs(pos - 1, 1, limit && i == up); + if (!limit && f[i][ok] != -1) { + return f[i][ok]; } - } - if (!limit) { - dp[pos][ok] = ans; - } - return ans; + int up = limit ? s[i] - '0' : 9; + int ans = 0; + for (int j = 0; j <= up; ++j) { + if (j == 0 || j == 1 || j == 8) { + ans += dfs(dfs, i + 1, ok, limit && j == up); + } else if (j == 2 || j == 5 || j == 6 || j == 9) { + ans += dfs(dfs, i + 1, 1, limit && j == up); + } + } + if (!limit) { + f[i][ok] = ans; + } + return ans; + }; + return dfs(dfs, 0, 0, true); } }; ``` @@ -346,46 +349,70 @@ public: ```go func rotatedDigits(n int) int { - a := make([]int, 6) - dp := make([][2]int, 6) - for i := range a { - dp[i] = [2]int{-1, -1} + s := strconv.Itoa(n) + m := len(s) + f := make([][2]int, m) + for i := range f { + f[i] = [2]int{-1, -1} } - l := 0 - for n > 0 { - l++ - a[l] = n % 10 - n /= 10 - } - - var dfs func(int, int, bool) int - dfs = func(pos, ok int, limit bool) int { - if pos <= 0 { + var dfs func(i, ok int, limit bool) int + dfs = func(i, ok int, limit bool) int { + if i >= m { return ok } - if !limit && dp[pos][ok] != -1 { - return dp[pos][ok] + if !limit && f[i][ok] != -1 { + return f[i][ok] } up := 9 if limit { - up = a[pos] + up = int(s[i] - '0') } ans := 0 - for i := 0; i <= up; i++ { - if i == 0 || i == 1 || i == 8 { - ans += dfs(pos-1, ok, limit && i == up) - } - if i == 2 || i == 5 || i == 6 || i == 9 { - ans += dfs(pos-1, 1, limit && i == up) + for j := 0; j <= up; j++ { + if j == 0 || j == 1 || j == 8 { + ans += dfs(i+1, ok, limit && j == up) + } else if j == 2 || j == 5 || j == 6 || j == 9 { + ans += dfs(i+1, 1, limit && j == up) } } if !limit { - dp[pos][ok] = ans + f[i][ok] = ans } return ans } + return dfs(0, 0, true) +} +``` + +#### TypeScript - return dfs(l, 0, true) +```ts +function rotatedDigits(n: number): number { + const s = n.toString(); + const m = s.length; + const f: number[][] = Array.from({ length: m }, () => Array(2).fill(-1)); + const dfs = (i: number, ok: number, limit: boolean): number => { + if (i >= m) { + return ok; + } + if (!limit && f[i][ok] !== -1) { + return f[i][ok]; + } + const up = limit ? +s[i] : 9; + let ans = 0; + for (let j = 0; j <= up; ++j) { + if ([0, 1, 8].includes(j)) { + ans += dfs(i + 1, ok, limit && j === up); + } else if ([2, 5, 6, 9].includes(j)) { + ans += dfs(i + 1, 1, limit && j === up); + } + } + if (!limit) { + f[i][ok] = ans; + } + return ans; + }; + return dfs(0, 0, true); } ``` diff --git a/solution/0700-0799/0788.Rotated Digits/README_EN.md b/solution/0700-0799/0788.Rotated Digits/README_EN.md index 4c75e42b35b27..4abf402156bab 100644 --- a/solution/0700-0799/0788.Rotated Digits/README_EN.md +++ b/solution/0700-0799/0788.Rotated Digits/README_EN.md @@ -67,7 +67,21 @@ Note that 1 and 10 are not good numbers, since they remain unchanged after rotat -### Solution 1 +### Solution 1: Direct Enumeration + +An intuitive and effective approach is to directly enumerate each number in $[1,2,..n]$ and determine whether it is a good number. If it is a good number, increment the answer by one. + +The key to the problem is how to determine whether a number $x$ is a good number. The logic is as follows: + +We first use an array $d$ of length 10 to record the rotated digits corresponding to each valid digit. In this problem, the valid digits are $[0, 1, 8, 2, 5, 6, 9]$, which correspond to the rotated digits $[0, 1, 8, 5, 2, 9, 6]$ respectively. If a digit is not valid, we set the corresponding rotated digit to $-1$. + +Then, we traverse each digit $v$ of the number $x$. If $v$ is not a valid digit, it means $x$ is not a good number, and we directly return $\textit{false}$. Otherwise, we add the rotated digit $d[v]$ corresponding to the digit $v$ to $y$. Finally, we check whether $x$ and $y$ are equal. If they are not equal, it means $x$ is a good number, and we return $\textit{true}$. + +The time complexity is $O(n \times \log n)$, where $n$ is the given number. The space complexity is $O(1)$. + +Similar problems: + +- [1056. Confusing Number](https://github.com/doocs/leetcode/blob/main/solution/1000-1099/1056.Confusing%20Number/README_EN.md) @@ -130,30 +144,28 @@ class Solution { ```cpp class Solution { public: - const vector d = {0, 1, 5, -1, -1, 2, 9, -1, 8, 6}; - int rotatedDigits(int n) { + int d[10] = {0, 1, 5, -1, -1, 2, 9, -1, 8, 6}; + auto check = [&](int x) -> bool { + int y = 0, t = x; + int k = 1; + while (t) { + int v = t % 10; + if (d[v] == -1) { + return false; + } + y = d[v] * k + y; + k *= 10; + t /= 10; + } + return x != y; + }; int ans = 0; for (int i = 1; i <= n; ++i) { ans += check(i); } return ans; } - - bool check(int x) { - int y = 0, t = x; - int k = 1; - while (t) { - int v = t % 10; - if (d[v] == -1) { - return false; - } - y = d[v] * k + y; - k *= 10; - t /= 10; - } - return x != y; - } }; ``` @@ -185,13 +197,75 @@ func rotatedDigits(n int) int { } ``` +#### TypeScript + +```ts +function rotatedDigits(n: number): number { + const d: number[] = [0, 1, 5, -1, -1, 2, 9, -1, 8, 6]; + const check = (x: number): boolean => { + let y = 0; + let t = x; + let k = 1; + + while (t > 0) { + const v = t % 10; + if (d[v] === -1) { + return false; + } + y = d[v] * k + y; + k *= 10; + t = Math.floor(t / 10); + } + return x !== y; + }; + return Array.from({ length: n }, (_, i) => i + 1).filter(check).length; +} +``` + -### Solution 2 +### Solution 2: Digit DP + +Solution 1 is sufficient to solve this problem, but its time complexity is relatively high. If the data range of the problem reaches the level of $10^9$, the approach in Solution 1 will exceed the time limit. + +This problem essentially asks for the number of numbers in the given range $[l, ..r]$ that satisfy certain conditions. The conditions are related to the composition of the numbers rather than their size, so we can use the concept of Digit DP to solve it. In Digit DP, the size of the number has little impact on the complexity. + +For the range $[l, ..r]$ problem, we generally convert it to the problem of $[1, ..r]$ and then subtract the result of $[1, ..l - 1]$, i.e.: + +$$ +ans = \sum_{i=1}^{r} ans_i - \sum_{i=1}^{l-1} ans_i +$$ + +However, for this problem, we only need to find the value for the range $[1, ..r]$. + +Here, we use memoized search to implement Digit DP. We search from the starting point downwards, and at the lowest level, we get the number of solutions. We then return the answers layer by layer upwards, and finally get the final answer from the starting point of the search. + +The basic steps are as follows: + +We convert the number $n$ to a string $s$. Then we define a function $\textit{dfs}(i, \textit{ok}, \textit{limit})$, where $i$ represents the digit position, $\textit{ok}$ indicates whether the current number satisfies the problem's conditions, and $\textit{limit}$ is a boolean indicating whether the digits that can be filled are restricted. + +The function executes as follows: + +If $i$ is greater than or equal to the length of the string $s$, return $\textit{ok}$; + +Otherwise, we get the current digit $up$. If $\textit{limit}$ is $\textit{true}$, $up$ is the current digit; otherwise, $up$ is $9$; + +Next, we iterate over $[0, ..up]$. If $j$ is a valid digit $[0, 1, 8]$, we recursively call $\textit{dfs}(i + 1, \textit{ok}, \textit{limit} \land j = \textit{up})$; if $j$ is a valid digit $[2, 5, 6, 9]$, we recursively call $\textit{dfs}(i + 1, 1, \textit{limit} \land j = \textit{up})$. We sum all the results of the recursive calls and return. + +The time complexity is $O(\log n \times D)$, and the space complexity is $O(\log n)$. Here, $D = 10$. + +Similar problems: + +- [233. Number of Digit One](https://github.com/doocs/leetcode/blob/main/solution/0200-0299/0233.Number%20of%20Digit%20One/README_EN.md) +- [357. Count Numbers with Unique Digits](https://github.com/doocs/leetcode/blob/main/solution/0300-0399/0357.Count%20Numbers%20with%20Unique%20Digits/README_EN.md) +- [600. Non-negative Integers without Consecutive Ones](https://github.com/doocs/leetcode/blob/main/solution/0600-0699/0600.Non-negative%20Integers%20without%20Consecutive%20Ones/README_EN.md) +- [902. Numbers At Most N Given Digit Set](https://github.com/doocs/leetcode/blob/main/solution/0900-0999/0902.Numbers%20At%20Most%20N%20Given%20Digit%20Set/README_EN.md) +- [1012. Numbers with Repeated Digits](https://github.com/doocs/leetcode/blob/main/solution/1000-1099/1012.Numbers%20With%20Repeated%20Digits/README_EN.md) +- [2376. Count Special Integers](https://github.com/doocs/leetcode/blob/main/solution/2300-2399/2376.Count%20Special%20Integers/README_EN.md) @@ -201,65 +275,53 @@ func rotatedDigits(n int) int { class Solution: def rotatedDigits(self, n: int) -> int: @cache - def dfs(pos, ok, limit): - if pos <= 0: + def dfs(i: int, ok: int, limit: bool) -> int: + if i >= len(s): return ok - up = a[pos] if limit else 9 + up = int(s[i]) if limit else 9 ans = 0 - for i in range(up + 1): - if i in (0, 1, 8): - ans += dfs(pos - 1, ok, limit and i == up) - if i in (2, 5, 6, 9): - ans += dfs(pos - 1, 1, limit and i == up) + for j in range(up + 1): + if j in (0, 1, 8): + ans += dfs(i + 1, ok, limit and j == up) + elif j in (2, 5, 6, 9): + ans += dfs(i + 1, 1, limit and j == up) return ans - a = [0] * 6 - l = 1 - while n: - a[l] = n % 10 - n //= 10 - l += 1 - return dfs(l, 0, True) + s = str(n) + return dfs(0, 0, True) ``` #### Java ```java class Solution { - private int[] a = new int[6]; - private int[][] dp = new int[6][2]; + private char[] s; + private Integer[][] f; public int rotatedDigits(int n) { - int len = 0; - for (var e : dp) { - Arrays.fill(e, -1); - } - while (n > 0) { - a[++len] = n % 10; - n /= 10; - } - return dfs(len, 0, true); + s = String.valueOf(n).toCharArray(); + f = new Integer[s.length][2]; + return dfs(0, 0, true); } - private int dfs(int pos, int ok, boolean limit) { - if (pos <= 0) { + private int dfs(int i, int ok, boolean limit) { + if (i >= s.length) { return ok; } - if (!limit && dp[pos][ok] != -1) { - return dp[pos][ok]; + if (!limit && f[i][ok] != null) { + return f[i][ok]; } - int up = limit ? a[pos] : 9; + int up = limit ? s[i] - '0' : 9; int ans = 0; - for (int i = 0; i <= up; ++i) { - if (i == 0 || i == 1 || i == 8) { - ans += dfs(pos - 1, ok, limit && i == up); - } - if (i == 2 || i == 5 || i == 6 || i == 9) { - ans += dfs(pos - 1, 1, limit && i == up); + for (int j = 0; j <= up; ++j) { + if (j == 0 || j == 1 || j == 8) { + ans += dfs(i + 1, ok, limit && j == up); + } else if (j == 2 || j == 5 || j == 6 || j == 9) { + ans += dfs(i + 1, 1, limit && j == up); } } if (!limit) { - dp[pos][ok] = ans; + f[i][ok] = ans; } return ans; } @@ -271,40 +333,33 @@ class Solution { ```cpp class Solution { public: - int a[6]; - int dp[6][2]; - int rotatedDigits(int n) { - memset(dp, -1, sizeof dp); - int len = 0; - while (n) { - a[++len] = n % 10; - n /= 10; - } - return dfs(len, 0, true); - } - - int dfs(int pos, int ok, bool limit) { - if (pos <= 0) { - return ok; - } - if (!limit && dp[pos][ok] != -1) { - return dp[pos][ok]; - } - int up = limit ? a[pos] : 9; - int ans = 0; - for (int i = 0; i <= up; ++i) { - if (i == 0 || i == 1 || i == 8) { - ans += dfs(pos - 1, ok, limit && i == up); + string s = to_string(n); + int m = s.size(); + int f[m][2]; + memset(f, -1, sizeof(f)); + auto dfs = [&](auto&& dfs, int i, int ok, bool limit) -> int { + if (i >= m) { + return ok; } - if (i == 2 || i == 5 || i == 6 || i == 9) { - ans += dfs(pos - 1, 1, limit && i == up); + if (!limit && f[i][ok] != -1) { + return f[i][ok]; } - } - if (!limit) { - dp[pos][ok] = ans; - } - return ans; + int up = limit ? s[i] - '0' : 9; + int ans = 0; + for (int j = 0; j <= up; ++j) { + if (j == 0 || j == 1 || j == 8) { + ans += dfs(dfs, i + 1, ok, limit && j == up); + } else if (j == 2 || j == 5 || j == 6 || j == 9) { + ans += dfs(dfs, i + 1, 1, limit && j == up); + } + } + if (!limit) { + f[i][ok] = ans; + } + return ans; + }; + return dfs(dfs, 0, 0, true); } }; ``` @@ -313,46 +368,70 @@ public: ```go func rotatedDigits(n int) int { - a := make([]int, 6) - dp := make([][2]int, 6) - for i := range a { - dp[i] = [2]int{-1, -1} + s := strconv.Itoa(n) + m := len(s) + f := make([][2]int, m) + for i := range f { + f[i] = [2]int{-1, -1} } - l := 0 - for n > 0 { - l++ - a[l] = n % 10 - n /= 10 - } - - var dfs func(int, int, bool) int - dfs = func(pos, ok int, limit bool) int { - if pos <= 0 { + var dfs func(i, ok int, limit bool) int + dfs = func(i, ok int, limit bool) int { + if i >= m { return ok } - if !limit && dp[pos][ok] != -1 { - return dp[pos][ok] + if !limit && f[i][ok] != -1 { + return f[i][ok] } up := 9 if limit { - up = a[pos] + up = int(s[i] - '0') } ans := 0 - for i := 0; i <= up; i++ { - if i == 0 || i == 1 || i == 8 { - ans += dfs(pos-1, ok, limit && i == up) - } - if i == 2 || i == 5 || i == 6 || i == 9 { - ans += dfs(pos-1, 1, limit && i == up) + for j := 0; j <= up; j++ { + if j == 0 || j == 1 || j == 8 { + ans += dfs(i+1, ok, limit && j == up) + } else if j == 2 || j == 5 || j == 6 || j == 9 { + ans += dfs(i+1, 1, limit && j == up) } } if !limit { - dp[pos][ok] = ans + f[i][ok] = ans } return ans } + return dfs(0, 0, true) +} +``` - return dfs(l, 0, true) +#### TypeScript + +```ts +function rotatedDigits(n: number): number { + const s = n.toString(); + const m = s.length; + const f: number[][] = Array.from({ length: m }, () => Array(2).fill(-1)); + const dfs = (i: number, ok: number, limit: boolean): number => { + if (i >= m) { + return ok; + } + if (!limit && f[i][ok] !== -1) { + return f[i][ok]; + } + const up = limit ? +s[i] : 9; + let ans = 0; + for (let j = 0; j <= up; ++j) { + if ([0, 1, 8].includes(j)) { + ans += dfs(i + 1, ok, limit && j === up); + } else if ([2, 5, 6, 9].includes(j)) { + ans += dfs(i + 1, 1, limit && j === up); + } + } + if (!limit) { + f[i][ok] = ans; + } + return ans; + }; + return dfs(0, 0, true); } ``` diff --git a/solution/0700-0799/0788.Rotated Digits/Solution.cpp b/solution/0700-0799/0788.Rotated Digits/Solution.cpp index 8505024081f2f..843aee3bc5c81 100644 --- a/solution/0700-0799/0788.Rotated Digits/Solution.cpp +++ b/solution/0700-0799/0788.Rotated Digits/Solution.cpp @@ -1,27 +1,25 @@ class Solution { public: - const vector d = {0, 1, 5, -1, -1, 2, 9, -1, 8, 6}; - int rotatedDigits(int n) { + int d[10] = {0, 1, 5, -1, -1, 2, 9, -1, 8, 6}; + auto check = [&](int x) -> bool { + int y = 0, t = x; + int k = 1; + while (t) { + int v = t % 10; + if (d[v] == -1) { + return false; + } + y = d[v] * k + y; + k *= 10; + t /= 10; + } + return x != y; + }; int ans = 0; for (int i = 1; i <= n; ++i) { ans += check(i); } return ans; } - - bool check(int x) { - int y = 0, t = x; - int k = 1; - while (t) { - int v = t % 10; - if (d[v] == -1) { - return false; - } - y = d[v] * k + y; - k *= 10; - t /= 10; - } - return x != y; - } -}; \ No newline at end of file +}; diff --git a/solution/0700-0799/0788.Rotated Digits/Solution.ts b/solution/0700-0799/0788.Rotated Digits/Solution.ts new file mode 100644 index 0000000000000..0de8c9fd366d0 --- /dev/null +++ b/solution/0700-0799/0788.Rotated Digits/Solution.ts @@ -0,0 +1,20 @@ +function rotatedDigits(n: number): number { + const d: number[] = [0, 1, 5, -1, -1, 2, 9, -1, 8, 6]; + const check = (x: number): boolean => { + let y = 0; + let t = x; + let k = 1; + + while (t > 0) { + const v = t % 10; + if (d[v] === -1) { + return false; + } + y = d[v] * k + y; + k *= 10; + t = Math.floor(t / 10); + } + return x !== y; + }; + return Array.from({ length: n }, (_, i) => i + 1).filter(check).length; +} diff --git a/solution/0700-0799/0788.Rotated Digits/Solution2.cpp b/solution/0700-0799/0788.Rotated Digits/Solution2.cpp index c066f45eccf3f..f4567951dd21a 100644 --- a/solution/0700-0799/0788.Rotated Digits/Solution2.cpp +++ b/solution/0700-0799/0788.Rotated Digits/Solution2.cpp @@ -1,38 +1,31 @@ class Solution { public: - int a[6]; - int dp[6][2]; - int rotatedDigits(int n) { - memset(dp, -1, sizeof dp); - int len = 0; - while (n) { - a[++len] = n % 10; - n /= 10; - } - return dfs(len, 0, true); - } - - int dfs(int pos, int ok, bool limit) { - if (pos <= 0) { - return ok; - } - if (!limit && dp[pos][ok] != -1) { - return dp[pos][ok]; - } - int up = limit ? a[pos] : 9; - int ans = 0; - for (int i = 0; i <= up; ++i) { - if (i == 0 || i == 1 || i == 8) { - ans += dfs(pos - 1, ok, limit && i == up); + string s = to_string(n); + int m = s.size(); + int f[m][2]; + memset(f, -1, sizeof(f)); + auto dfs = [&](auto&& dfs, int i, int ok, bool limit) -> int { + if (i >= m) { + return ok; + } + if (!limit && f[i][ok] != -1) { + return f[i][ok]; + } + int up = limit ? s[i] - '0' : 9; + int ans = 0; + for (int j = 0; j <= up; ++j) { + if (j == 0 || j == 1 || j == 8) { + ans += dfs(dfs, i + 1, ok, limit && j == up); + } else if (j == 2 || j == 5 || j == 6 || j == 9) { + ans += dfs(dfs, i + 1, 1, limit && j == up); + } } - if (i == 2 || i == 5 || i == 6 || i == 9) { - ans += dfs(pos - 1, 1, limit && i == up); + if (!limit) { + f[i][ok] = ans; } - } - if (!limit) { - dp[pos][ok] = ans; - } - return ans; + return ans; + }; + return dfs(dfs, 0, 0, true); } -}; \ No newline at end of file +}; diff --git a/solution/0700-0799/0788.Rotated Digits/Solution2.go b/solution/0700-0799/0788.Rotated Digits/Solution2.go index 065c3e74e40c4..b4e5609fab029 100644 --- a/solution/0700-0799/0788.Rotated Digits/Solution2.go +++ b/solution/0700-0799/0788.Rotated Digits/Solution2.go @@ -1,42 +1,34 @@ func rotatedDigits(n int) int { - a := make([]int, 6) - dp := make([][2]int, 6) - for i := range a { - dp[i] = [2]int{-1, -1} + s := strconv.Itoa(n) + m := len(s) + f := make([][2]int, m) + for i := range f { + f[i] = [2]int{-1, -1} } - l := 0 - for n > 0 { - l++ - a[l] = n % 10 - n /= 10 - } - - var dfs func(int, int, bool) int - dfs = func(pos, ok int, limit bool) int { - if pos <= 0 { + var dfs func(i, ok int, limit bool) int + dfs = func(i, ok int, limit bool) int { + if i >= m { return ok } - if !limit && dp[pos][ok] != -1 { - return dp[pos][ok] + if !limit && f[i][ok] != -1 { + return f[i][ok] } up := 9 if limit { - up = a[pos] + up = int(s[i] - '0') } ans := 0 - for i := 0; i <= up; i++ { - if i == 0 || i == 1 || i == 8 { - ans += dfs(pos-1, ok, limit && i == up) - } - if i == 2 || i == 5 || i == 6 || i == 9 { - ans += dfs(pos-1, 1, limit && i == up) + for j := 0; j <= up; j++ { + if j == 0 || j == 1 || j == 8 { + ans += dfs(i+1, ok, limit && j == up) + } else if j == 2 || j == 5 || j == 6 || j == 9 { + ans += dfs(i+1, 1, limit && j == up) } } if !limit { - dp[pos][ok] = ans + f[i][ok] = ans } return ans } - - return dfs(l, 0, true) -} \ No newline at end of file + return dfs(0, 0, true) +} diff --git a/solution/0700-0799/0788.Rotated Digits/Solution2.java b/solution/0700-0799/0788.Rotated Digits/Solution2.java index 3c7068f5cc1f1..d2578f1333f93 100644 --- a/solution/0700-0799/0788.Rotated Digits/Solution2.java +++ b/solution/0700-0799/0788.Rotated Digits/Solution2.java @@ -1,39 +1,32 @@ class Solution { - private int[] a = new int[6]; - private int[][] dp = new int[6][2]; + private char[] s; + private Integer[][] f; public int rotatedDigits(int n) { - int len = 0; - for (var e : dp) { - Arrays.fill(e, -1); - } - while (n > 0) { - a[++len] = n % 10; - n /= 10; - } - return dfs(len, 0, true); + s = String.valueOf(n).toCharArray(); + f = new Integer[s.length][2]; + return dfs(0, 0, true); } - private int dfs(int pos, int ok, boolean limit) { - if (pos <= 0) { + private int dfs(int i, int ok, boolean limit) { + if (i >= s.length) { return ok; } - if (!limit && dp[pos][ok] != -1) { - return dp[pos][ok]; + if (!limit && f[i][ok] != null) { + return f[i][ok]; } - int up = limit ? a[pos] : 9; + int up = limit ? s[i] - '0' : 9; int ans = 0; - for (int i = 0; i <= up; ++i) { - if (i == 0 || i == 1 || i == 8) { - ans += dfs(pos - 1, ok, limit && i == up); - } - if (i == 2 || i == 5 || i == 6 || i == 9) { - ans += dfs(pos - 1, 1, limit && i == up); + for (int j = 0; j <= up; ++j) { + if (j == 0 || j == 1 || j == 8) { + ans += dfs(i + 1, ok, limit && j == up); + } else if (j == 2 || j == 5 || j == 6 || j == 9) { + ans += dfs(i + 1, 1, limit && j == up); } } if (!limit) { - dp[pos][ok] = ans; + f[i][ok] = ans; } return ans; } -} \ No newline at end of file +} diff --git a/solution/0700-0799/0788.Rotated Digits/Solution2.py b/solution/0700-0799/0788.Rotated Digits/Solution2.py index 14e41e6f35aa0..77c1afc25ff63 100644 --- a/solution/0700-0799/0788.Rotated Digits/Solution2.py +++ b/solution/0700-0799/0788.Rotated Digits/Solution2.py @@ -1,22 +1,17 @@ class Solution: def rotatedDigits(self, n: int) -> int: @cache - def dfs(pos, ok, limit): - if pos <= 0: + def dfs(i: int, ok: int, limit: bool) -> int: + if i >= len(s): return ok - up = a[pos] if limit else 9 + up = int(s[i]) if limit else 9 ans = 0 - for i in range(up + 1): - if i in (0, 1, 8): - ans += dfs(pos - 1, ok, limit and i == up) - if i in (2, 5, 6, 9): - ans += dfs(pos - 1, 1, limit and i == up) + for j in range(up + 1): + if j in (0, 1, 8): + ans += dfs(i + 1, ok, limit and j == up) + elif j in (2, 5, 6, 9): + ans += dfs(i + 1, 1, limit and j == up) return ans - a = [0] * 6 - l = 1 - while n: - a[l] = n % 10 - n //= 10 - l += 1 - return dfs(l, 0, True) + s = str(n) + return dfs(0, 0, True) diff --git a/solution/0700-0799/0788.Rotated Digits/Solution2.ts b/solution/0700-0799/0788.Rotated Digits/Solution2.ts new file mode 100644 index 0000000000000..36ea091952662 --- /dev/null +++ b/solution/0700-0799/0788.Rotated Digits/Solution2.ts @@ -0,0 +1,27 @@ +function rotatedDigits(n: number): number { + const s = n.toString(); + const m = s.length; + const f: number[][] = Array.from({ length: m }, () => Array(2).fill(-1)); + const dfs = (i: number, ok: number, limit: boolean): number => { + if (i >= m) { + return ok; + } + if (!limit && f[i][ok] !== -1) { + return f[i][ok]; + } + const up = limit ? +s[i] : 9; + let ans = 0; + for (let j = 0; j <= up; ++j) { + if ([0, 1, 8].includes(j)) { + ans += dfs(i + 1, ok, limit && j === up); + } else if ([2, 5, 6, 9].includes(j)) { + ans += dfs(i + 1, 1, limit && j === up); + } + } + if (!limit) { + f[i][ok] = ans; + } + return ans; + }; + return dfs(0, 0, true); +}