We can rotate digits by 180 degrees to form new digits. When 0, 1, 6, 8, 9 are rotated 180 degrees, they become 0, 1, 9, 8, 6 respectively. When 2, 3, 4, 5 and 7 are rotated 180 degrees, they become invalid.
A confusing number is a number that when rotated 180 degrees becomes a different number with each digit valid.(Note that the rotated number can be greater than the original number.)
Given a positive integer N
, return the number of confusing numbers between 1
and N
inclusive.
Example 1:
Input: 20
Output: 6
Explanation:
The confusing numbers are [6,9,10,16,18,19].
6 converts to 9.
9 converts to 6.
10 converts to 01 which is just 1.
16 converts to 91.
18 converts to 81.
19 converts to 61.
Example 2:
Input: 100
Output: 19
Explanation:
The confusing numbers are [6,9,10,16,18,19,60,61,66,68,80,81,86,89,90,91,98,99,100].
Note:
1 <= N <= 10^9
解題思路:
首先將N轉換成字符串,求其長度
string ns = to_string(N) ;
int nlen = ns.size() ;
然後對於所有長度小於ns符合條件的字符串,一定是小於N的,可以直接加到結果中;
for(int len = nlen - 1 ; len >= 2 ; len--)
{
if(len == 2)
{
nt += 4 * 4 ;
continue;
}
cnt += limit_all(len) - limit_palin(len) ;
}
如何求滿足長度小於ns又符合條件的字符串:
求{0,1,6,8,9}的所有長度爲len的排列數:
int limit_all(int len)
{
int res = 4 ;
len-- ;
while(len > 0)
{
res *= 5 ;
len-- ;
}
return res ;
}
求{0,1,6,8,9}的所有長度爲len的但是nonconfused的數:
int limit_palin(int len)
{
if(len % 2)
{
int res = 3 ;
res *= 4 ;
len = (len - 3) / 2 ;
while(len > 0)
{
res *= 5 ;
len-- ;
}
return res ;
}
else
{
int res = 4 ;
len = (len - 2) / 2 ;
while(len > 0)
{
res *= 5 ;
len-- ;
}
return res ;
}
}
兩者相減,得到的就是長度爲len而且confused的數;
然後開始構造由{0,1,6,8,9}構成的偶位數 ;在空字符串的兩邊添加字符 ;
unordered_map<string, bool> backtrack(string base , bool islimited , int nlen)
{
unordered_map<string , bool> res ;
for(auto f : rotated_num)
for(auto l : rotated_num)
{
string new_base = string(1 , f) + base + string(1 , l) ;
if(new_base.size() <= nlen)
{
unordered_map<string , bool> ret ;
if(islimited || l != corre_num[f]) ret = backtrack(new_base , true , nlen) ;
else ret = backtrack(new_base , false , nlen) ;
if(!ret.empty()) res.insert(ret.begin() , ret.end()) ;
if(new_base.size() < nlen - 1 || f == '0') continue ;
if(islimited || l != corre_num[f]) res[new_base] = true ;
else res[new_base] = false ;
//cout<<"new_base:"<<new_base<<" "<<res[new_base]<<endl;
}
else return {} ;
}
return res ;
}
unordered_map[string] = bool 是爲了判斷string是否符合confused number的條件 , 符合爲true , 不符合爲false ;
只需要長度爲nlen或者nlen - 1的字符串 , 因爲長度更小的字符串已經添加到結果中了,這樣可以減少ret的遍歷次數 ;
不允許字符串的第一個字符爲'0' , 因爲數字的第一位不可能是0 ;
然後對ret中的字符串進行遍歷
for(auto ele : ret)
{
if(ele.first.size() == nlen )
{
if(ele.second && ele.first >= ones && ele.first <= ns) cnt++ ;
continue ;
}
for(auto c : rotated_num)
{
if(c == '6' || c == '9')
{
string s = ele.first.substr(0 , ele.first.size() / 2) + c + ele.first.substr(ele.first.size() / 2) ;
if(s >= ones && s <= ns) cnt++ ;
}
else
{
if(ele.second)
{
string s = ele.first.substr(0 , ele.first.size() / 2) + c + ele.first.substr(ele.first.size() / 2) ;
if(s >= ones && s <= ns) cnt++ ;
}
}
}
}
優化:用排除法,先求{0 , 1 , 6 , 8 , 9}的所有排列數 ;
int limit_all(string s)
{
if(s.empty()) return 0 ;
string digits = "01689" ;
int res = 0 , smaller = 0;
for(auto c : digits)
{
if(s.size() == 1) smaller += c <= s[0] ;
else smaller += c < s[0] ;
}
if(s.size() == 1) return smaller ;
if(smaller)
{
res += smaller * (int)pow(5 , s.size() - 1) ;
}
if(digits.find(s[0]) != string::npos)
{
res += limit_all(s.substr(1)) ;
}
return res ;
}
因爲其中包含了0 , 所以最後還要減去0 ;
然後求所有的nonconfused的數
int limit_palin(string ns , int N)
{
vector<string> pairs = {"00" , "11" , "69" , "88" , "96"} ;
unordered_map<int , vector<string>> nonconfused ;
int res = 0 ;
nonconfused[0] = {""} ;
for(int len = 1 ; len <= ns.size() ; ++len)
{
if(len == 1)
{
for(auto pair : pairs)
{
if(pair[0] == '6' || pair[0] == '9') continue ;
nonconfused[1].push_back(pair.substr(0 , 1)) ;
long num = stol(pair.substr(0 , 1)) ;
if(num >= 1 && num <= N) res++ ;
}
}
else
{
for(auto s : nonconfused[len - 2])
{
for(auto pair : pairs)
{
string new_s = pair[0] + s + pair[1] ;
nonconfused[len].push_back(new_s) ;
if(pair[0] == '0') continue ;
long num = stol(new_s) ;
if(num >= 1 && num <= N) res++ ;
}
}
}
}
return res ;
}
int confusingNumberII(int N)
{
string ns = to_string(N) ;
return limit_all(ns) - limit_palin(ns , N) - 1 ;
}