易混淆数(Confusing Number)指的是一个数字在整体旋转 180°
以后,能够得到一个和原来 不同 的数,且 新数字的每一位都应该是有效的。
本题我们会将数字旋转 180°
来生成一个新的数字。
- 当
0、1、6、8、9
旋转180°
以后,我们得到的新数字分别为 0、1、9、8、6。 - 当
2、3、4、5、7
旋转180°
后,是 无法 得到任何数字的。
请注意,在旋转一个数字之后,我们可以忽略前导零。
- 例如,在旋转
8000
之后,我们有0008
,它被认为只是8
。
给出正整数 n
,请你返回 [1, n]
范围内的 易混淆数 的数量 。
示例 1:
输入:n = 20 输出:6 解释:易混淆数为 [6,9,10,16,18,19]。 6 转换为 9 9 转换为 6 10 转换为 01 也就是 1 16 转换为 91 18 转换为 81 19 转换为 61
示例 2:
输入:n = 100 输出:19 解释:易混淆数为 [6,9,10,16,18,19,60,61,66,68,80,81,86,89,90,91,98,99,100]。
提示:
1 <= n <= 109
方法一:数位 DP
我们先将数字
接下来,我们定义一个函数
然后,我们定义另一个函数
- 参数
$pos$ 表示当前搜索到的位置,初始时为$0$ ; - 参数
$limit$ 表示当前搜索的数是否受到上界的限制,初始时为$true$ ; - 参数
$x$ 表示当前搜索的数,初始时为$0$ 。
在
否则,我们计算出当前位置上的数字的上界
最终的答案即为
时间复杂度
class Solution:
def confusingNumberII(self, n: int) -> int:
def check(x: int) -> bool:
y, t = 0, x
while t:
t, v = divmod(t, 10)
y = y * 10 + d[v]
return x != y
def dfs(pos: int, limit: bool, x: int) -> int:
if pos >= len(s):
return int(check(x))
up = int(s[pos]) if limit else 9
ans = 0
for i in range(up + 1):
if d[i] != -1:
ans += dfs(pos + 1, limit and i == up, x * 10 + i)
return ans
d = [0, 1, -1, -1, -1, -1, 9, -1, 8, 6]
s = str(n)
return dfs(0, True, 0)
class Solution {
private final int[] d = {0, 1, -1, -1, -1, -1, 9, -1, 8, 6};
private String s;
public int confusingNumberII(int n) {
s = String.valueOf(n);
return dfs(0, 1, 0);
}
private int dfs(int pos, int limit, int x) {
if (pos >= s.length()) {
return check(x) ? 1 : 0;
}
int up = limit == 1 ? s.charAt(pos) - '0' : 9;
int ans = 0;
for (int i = 0; i <= up; ++i) {
if (d[i] != -1) {
ans += dfs(pos + 1, limit == 1 && i == up ? 1 : 0, x * 10 + i);
}
}
return ans;
}
private boolean check(int x) {
int y = 0;
for (int t = x; t > 0; t /= 10) {
int v = t % 10;
y = y * 10 + d[v];
}
return x != y;
}
}
class Solution {
public:
int confusingNumberII(int n) {
string s = to_string(n);
int d[10] = {0, 1, -1, -1, -1, -1, 9, -1, 8, 6};
auto check = [&](int x) -> bool {
int y = 0;
for (int t = x; t; t /= 10) {
int v = t % 10;
y = y * 10 + d[v];
}
return x != y;
};
function<int(int, int, int)> dfs = [&](int pos, int limit, int x) -> int {
if (pos >= s.size()) {
return check(x);
}
int up = limit ? s[pos] - '0' : 9;
int ans = 0;
for (int i = 0; i <= up; ++i) {
if (d[i] != -1) {
ans += dfs(pos + 1, limit && i == up, x * 10 + i);
}
}
return ans;
};
return dfs(0, 1, 0);
}
};
func confusingNumberII(n int) int {
d := [10]int{0, 1, -1, -1, -1, -1, 9, -1, 8, 6}
s := strconv.Itoa(n)
check := func(x int) bool {
y := 0
for t := x; t > 0; t /= 10 {
v := t % 10
y = y*10 + d[v]
}
return x != y
}
var dfs func(pos int, limit bool, x int) int
dfs = func(pos int, limit bool, x int) (ans int) {
if pos >= len(s) {
if check(x) {
return 1
}
return 0
}
up := 9
if limit {
up = int(s[pos] - '0')
}
for i := 0; i <= up; i++ {
if d[i] != -1 {
ans += dfs(pos+1, limit && i == up, x*10+i)
}
}
return
}
return dfs(0, true, 0)
}
function confusingNumberII(n: number): number {
const s = n.toString();
const d: number[] = [0, 1, -1, -1, -1, -1, 9, -1, 8, 6];
const check = (x: number) => {
let y = 0;
for (let t = x; t > 0; t = Math.floor(t / 10)) {
const v = t % 10;
y = y * 10 + d[v];
}
return x !== y;
};
const dfs = (pos: number, limit: boolean, x: number): number => {
if (pos >= s.length) {
return check(x) ? 1 : 0;
}
const up = limit ? parseInt(s[pos]) : 9;
let ans = 0;
for (let i = 0; i <= up; ++i) {
if (d[i] !== -1) {
ans += dfs(pos + 1, limit && i === up, x * 10 + i);
}
}
return ans;
};
return dfs(0, true, 0);
}