comments | difficulty | edit_url | tags | ||
---|---|---|---|---|---|
true |
Medium |
|
An integer x
is a good if after rotating each digit individually by 180 degrees, we get a valid number that is different from x
. Each digit must be rotated - we cannot choose to leave it alone.
A number is valid if each digit remains a digit after rotation. For example:
0
,1
, and8
rotate to themselves,2
and5
rotate to each other (in this case they are rotated in a different direction, in other words,2
or5
gets mirrored),6
and9
rotate to each other, and- the rest of the numbers do not rotate to any other number and become invalid.
Given an integer n
, return the number of good integers in the range [1, n]
.
Example 1:
Input: n = 10 Output: 4 Explanation: There are four good numbers in the range [1, 10] : 2, 5, 6, 9. Note that 1 and 10 are not good numbers, since they remain unchanged after rotating.
Example 2:
Input: n = 1 Output: 0
Example 3:
Input: n = 2 Output: 1
Constraints:
1 <= n <= 104
An intuitive and effective approach is to directly enumerate each number in
The key to the problem is how to determine whether a number
We first use an array
Then, we traverse each digit
The time complexity is
Similar problems:
class Solution:
def rotatedDigits(self, n: int) -> int:
def check(x):
y, t = 0, x
k = 1
while t:
v = t % 10
if d[v] == -1:
return False
y = d[v] * k + y
k *= 10
t //= 10
return x != y
d = [0, 1, 5, -1, -1, 2, 9, -1, 8, 6]
return sum(check(i) for i in range(1, n + 1))
class Solution {
private int[] d = new int[] {0, 1, 5, -1, -1, 2, 9, -1, 8, 6};
public int rotatedDigits(int n) {
int ans = 0;
for (int i = 1; i <= n; ++i) {
if (check(i)) {
++ans;
}
}
return ans;
}
private boolean check(int x) {
int y = 0, t = x;
int k = 1;
while (t > 0) {
int v = t % 10;
if (d[v] == -1) {
return false;
}
y = d[v] * k + y;
k *= 10;
t /= 10;
}
return x != y;
}
}
class Solution {
public:
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;
}
};
func rotatedDigits(n int) int {
d := []int{0, 1, 5, -1, -1, 2, 9, -1, 8, 6}
check := func(x int) bool {
y, t := 0, x
k := 1
for ; t > 0; t /= 10 {
v := t % 10
if d[v] == -1 {
return false
}
y = d[v]*k + y
k *= 10
}
return x != y
}
ans := 0
for i := 1; i <= n; i++ {
if check(i) {
ans++
}
}
return ans
}
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 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
This problem essentially asks for the number of numbers in the given range
For the range
However, for this problem, we only need to find the value for the range
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
The function executes as follows:
If
Otherwise, we get the current digit
Next, we iterate over
The time complexity is
Similar problems:
- 233. Number of Digit One
- 357. Count Numbers with Unique Digits
- 600. Non-negative Integers without Consecutive Ones
- 902. Numbers At Most N Given Digit Set
- 1012. Numbers with Repeated Digits
- 2376. Count Special Integers
class Solution:
def rotatedDigits(self, n: int) -> int:
@cache
def dfs(i: int, ok: int, limit: bool) -> int:
if i >= len(s):
return ok
up = int(s[i]) if limit else 9
ans = 0
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
s = str(n)
return dfs(0, 0, True)
class Solution {
private char[] s;
private Integer[][] f;
public int rotatedDigits(int n) {
s = String.valueOf(n).toCharArray();
f = new Integer[s.length][2];
return dfs(0, 0, true);
}
private int dfs(int i, int ok, boolean limit) {
if (i >= s.length) {
return ok;
}
if (!limit && f[i][ok] != null) {
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(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) {
f[i][ok] = ans;
}
return ans;
}
}
class Solution {
public:
int rotatedDigits(int n) {
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 (!limit) {
f[i][ok] = ans;
}
return ans;
};
return dfs(dfs, 0, 0, true);
}
};
func rotatedDigits(n int) int {
s := strconv.Itoa(n)
m := len(s)
f := make([][2]int, m)
for i := range f {
f[i] = [2]int{-1, -1}
}
var dfs func(i, ok int, limit bool) int
dfs = func(i, ok int, limit bool) int {
if i >= m {
return ok
}
if !limit && f[i][ok] != -1 {
return f[i][ok]
}
up := 9
if limit {
up = int(s[i] - '0')
}
ans := 0
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 {
f[i][ok] = ans
}
return ans
}
return dfs(0, 0, true)
}
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);
}