跳转至

1088. 易混淆数 II 🔒

题目描述

易混淆数(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

我们先将数字 $n$ 转成字符串 $s$。

接下来,我们定义一个函数 $check(x)$,用来判断 $x$ 在旋转 $180^\circ$ 之后是否变成了一个不同的数。如果 $x$ 在旋转 $180^\circ$ 之后变成了一个不同的数,那么我们就称 $x$ 是一个易混淆数。

然后,我们定义另一个函数 $dfs(pos, limit, x)$,用于搜索从高位到低位的每一位。其中:

  • 参数 $pos$ 表示当前搜索到的位置,初始时为 $0$;
  • 参数 $limit$ 表示当前搜索的数是否受到上界的限制,初始时为 $true$;
  • 参数 $x$ 表示当前搜索的数,初始时为 $0$。

在 $dfs(pos, limit, x)$ 中,如果 $pos \geq len(s)$,那么我们就判断 $x$ 是否是一个易混淆数,如果是则返回 $1$,否则返回 $0$。

否则,我们计算出当前位置上的数字的上界 $up$,然后枚举当前位置上的数字 $i$,如果 $i$ 在旋转 $180^\circ$ 之后不是一个数字,那么我们就直接跳过这个数字。否则,我们将 $x$ 更新为 $x \times 10 + i$,并根据 $limit$ 的值决定下一步搜索的时候是否受到上界的限制,最后将答案返回。

最终的答案即为 $dfs(0, true, 0)$。

时间复杂度 $O(5^{\log_{10}n})$,空间复杂度 $O(\log_{10}n)$。其中 $5^{\log_{10}n}$ 表示 $n$ 的位数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
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)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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);
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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);
}

评论