leetcode 1088. Confusing Number II

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. 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 ;
    }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章