# 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; } } ```