Skip to content

feat: add solutions to lc problem: No.0788 #3543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
271 changes: 149 additions & 122 deletions solution/0700-0799/0788.Rotated Digits/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ tags:

<pre><strong>输入:</strong> 10
<strong>输出:</strong> 4
<strong>解释:</strong>
<strong>解释:</strong>
在[1, 10]中有四个好数: 2, 5, 6, 9。
注意 1 和 10 不是好数, 因为他们在旋转之后不变。
</pre>
Expand All @@ -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)$。

相似题目:

Expand Down Expand Up @@ -125,30 +125,28 @@ class Solution {
```cpp
class Solution {
public:
const vector<int> 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;
}
};
```

Expand Down Expand Up @@ -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;
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand All @@ -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$。

相似题目:

Expand All @@ -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;
}
Expand All @@ -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);
}
};
```
Expand All @@ -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);
}
```

Expand Down
Loading
Loading