---
# System prepended metadata

title: 1088. Confusing Number II
tags: [Leetcode, Hard, Math, Backtracking]

---

# 1088. Confusing Number II
###### tags: `Leetcode` `Hard` `Backtracking` `Math`
Link: https://leetcode.com/problems/confusing-number-ii/
## 思路
直觉的想法是用backtracking
但其实是有点没效率的 因为例如n的长度=5 那么我们可以用数学方法算出来长度小于等于4的confusing number一共有多少个
然后再用backtracking算长度等于5且小于n的confusing number

数学方法为:
首先，我们知道confusing number只能用0,1,6,8,9这五个数字组数。先考虑给定这个digit集合能组成多少个长度为len的数？显然答案是```4*pow(5,len-1)```，其中4是考虑到了高位首位不能为零。

然后我们考虑在上述这些数中间有多少non-confusing number呢？Non-confusing number的定义就是翻转之后和原来的数字一样，也就是说，相对中间位置对称的两个digit需要是翻转对称的（也就是1->1,6->9,8->8,9->6,0->0），并且如果长度是奇数那么中间一个digit与自己翻转堆成（也就是1->1,8->8,0->0）.所以对于长度为len的数，non-confusing number的个数的计算方法：
```
if (len%2==0)        
    return 4*pow(5,len/2-1);
else
    return 4*pow(5,len/2-1)*3;
```
同理，4表示高位第一位不能是0，所以是四种选择。3表示长度是奇数时，中间一个digit的选择只有三种。其他位置（从高位第一位到中间一位）的选择是五种。```len/2```的操作是因为，对于non-confusing number，只要确定了前一般长度的digit，后一半的digit也就确定了。

所以对于长度等于len的confusing number，就是上面计算得到的两个结果之差。

**注意**: 当len=1时特别考虑因为```4*pow(5, len/2-1)*3```在len=1时会变成0 len=1时有两个confusing number

然后我们再用backtracking算出小于n并且长度等于n的长度的confusing number的个数
## Code
```java=
class Solution {
    int ans;
    public int confusingNumberII(int n) {
        int len = String.valueOf(n).length();
        ans = 2;
        for(int i=2; i<len; i++){
            ans += confusingNumberGivenLen(i);
        }
        int[] num = new int[]{0,1,6,8,9};
        backtracking(num, 0, 0L, len, n);
        return ans;
    }
    public void backtracking(int[] num, int currLen, long currNum, int len, int n){
        if(currLen==len){
            if(currNum<=n && isConfusingNumber(currNum)){
                ans++;
            }
            return;
        }
        currNum *= 10;
        for(int i=0; i<num.length; i++){
            if(currLen==0 && i==0) continue;
            backtracking(num, currLen+1, currNum+num[i], len, n);
        }
    }
    public int confusingNumberGivenLen(int len){
        long ans = 4*(int)Math.pow(5, len-1);
        if(len%2==0) ans -= 4*(int)Math.pow(5, len/2-1);
        else ans -= 4*(int)Math.pow(5, len/2-1)*3;
        return (int)ans;
    }
    public boolean isConfusingNumber(long n){
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0,0);
        map.put(1,1);
        map.put(8,8);
        map.put(6,9);
        map.put(9,6);
        char[] arr = String.valueOf(n).toCharArray();
        int left=0, right = arr.length-1;
        while(left<=right){
            if(map.get(arr[left]-'0')!=arr[right]-'0') return true;
            left++;
            right--;
        }
        return false;
    }
}
```