639. Decode Ways II

#639. Decode Ways II

題目來源:

https://leetcode.com/problems/decode-ways-ii/description/

題意分析:

存在一個映射把"A"-"Z"映射到1-26。給定一串包含數字喝和"*"的字符串,'*'可以表示1-9的任意數字。求出解碼爲字母的方式的數目。返回結果對10^9+7取餘。

hint:這題是#91. Decode Ways的延伸,建議先做了91題。

 例子:


    

題目思路:

(如果不想看前面超時的解可以直接拉到最後看AC的解)

因爲在91題已經實現了無"*"求解的代碼,這題想着只要把"*"逐一替換爲1-9,求出所有可能的字符串,然後每個字符串分別計算並求和即可。可惜提交後是超時的,我輸出所有的字符串,發現可以以每9個字符串爲一組,第1個即某個"*"替換成了1,第2個即某個"*"替換成了1,以此類推。其中第3、4、5、6求到的數目是相同的(因爲無論前一位是什麼都不影響),第7,8,9也是相同的(3,4,5,6可能會跟前面組成23,24,25,26.而7,8,9不行,所以兩者不同),第1、2特殊要獨立求。

舉個栗子:輸入爲"1**1",那麼部分輸出爲


那麼就可以優化一丟丟。

class Solution {
private:
    vector<string> all_str;


public:
    int numDecodings(string s) {
        bool flag=true;
        for (int i=0; i<s.size(); i++){
            if (s[i]=='*'){
                flag=false;
                break;
            }
        }
        if (flag) return numDecodingsConfirm(s);
        generate(s,0);
        int res=0;
        // cout<<all_str.size()<<endl;
        for (int i=0; i<all_str.size();i+=9){
            int temp=numDecodingsConfirm(all_str[i]);
            // cout<<all_str[i]<<" "<<temp<<endl;
            res=(res+temp)%100000007;
            temp=numDecodingsConfirm(all_str[i+1]);
            // cout<<all_str[i]<<" "<<temp<<endl;
            res=(res+temp)%100000007;
            temp=numDecodingsConfirm(all_str[i+2]);
            // cout<<all_str[i+2]<<" "<<temp<<endl;
            res=(res+temp*4)%100000007;
            temp=numDecodingsConfirm(all_str[i+6]);
            // cout<<all_str[i+6]<<" "<<temp<<endl;
            res=(res+temp*3)%100000007;
        }
        // for(int i=0; i<all_str.size(); i++){
        //     int temp=numDecodingsConfirm(all_str[i]);
        //     cout<<all_str[i]<<" "<<temp<<endl;       
        //     res=(res+temp)%100000007;
        // }
        return res;
    }
    void generate(string& s, int idx){
        if (idx==s.size()){
            // cout<<s<<endl;
            all_str.push_back(s);
            return ;
        }
        if (s[idx]!='*')
            generate(s,idx+1);
        else{
            for(int i=1; i<=9; i++){
                s[idx]=i+'0';
                generate(s,idx+1);
                s[idx]='*';
            }
        }
        return ;
    }
    int numDecodingsConfirm(string s) {
        if (s.size()<=1){
            if(s.size()==1&&s[0]=='0'||s.size()==0)
                return 0;
            else
                return 1;
        }
        vector<int> res(s.size(),0);
        int count=s[0]-'0';
        count=count*10+s[1]-'0';
        if (count<=9){
            res[0]=0; res[1]=0;
        }
        else if (count==10||count==20){
            res[0]=1;res[1]=1;
        }
        else if (count<=26){
            res[0]=1;res[1]=2;
        }
        else if (count%10==0){
            res[0]=1;res[1]=0;
        }
        else{
            res[0]=1;res[1]=1;
        }
        
        
        for (int i=2; i<s.size(); i++){
            if (s[i]!='0')
                res[i]=res[i-1];
            if(s[i-1]=='1'||s[i-1]=='2'&&s[i]<='6')
                res[i]+=res[i-2];
        }
        return res[s.size()-1];
            
    }
}; 

很遺憾的是還是超時了。


Discuss裏大佬的解

class Solution {
public:
    int numDecodings(string s) {
        long e0 = 1, e1 = 0, e2 = 0, f0, f1, f2;
        for ( char c : s ) {
            if ( '*' == c ) {
                f0 = 9 * e0 + 9 * e1 + 6 * e2;
                f1 = f2 = e0;
            } else {
                f0 = int(c > '0') * e0 + e1 + int(c < '7') * e2;
                f1 = '1' == c ? e0 : 0;
                f2 = '2' == c ? e0 : 0;
            }
            e0 = f0 % 1000000007;
            e1 = f1;
            e2 = f2;
        }
        return int(e0);
    }
};

代碼解釋

    字符串從左往右遍歷,每個階段中

  •         e0表示當前結尾可以是任意字符且結尾不成雙的解碼方式數目
  •         e1表示當前結尾只能是1,且這個1需要跟後面的數字成雙的解碼方式數目
  •         e2表示當前結尾只能是2,且這個2需要跟後面的數字成雙的解碼方式數目

    用f0、f1、f2更新e0、e1、e2 。對於字符c

  •     如果c=='*',f0 = 9 * e0 + 9 * e1 + 6 * e2。很容易理解,f1 = f2 = e0;相當於在末尾加上一個1或者2,數目不變。
  •     如果c!='*',  可以把c當做單獨的一個數字,只要c!=‘0’(+e0);如果前一位是'1',c無論是什麼都可以跟前一位成雙(+e1);如果前一位是'2',那麼c只能是'0'-'6'才能跟前一位成雙(+e2),所以總的式子爲

           f0 = int(c > '0') * e0 + e1 + int(c < '7') * e2;

            此時如果c=='1',那麼f1=e0,即把c附加在後面,否則f1=0.

            f2同理。

最後返回e0即可。

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