JavaScript|LeetCode|动态规划|91.解码方法

法1:动态规划
想法:

  1. 用数组dp保存以当前数字字符结尾的串的解码方法总数
  2. 对于当前数字字符s[i],若s[i - 1]s[i]衔接而成的数字可解码(即 >=1 且 <= 26),则dp[i] = dp[i - 2] + dp[i - 1](dp[i - 2]表示s[i - 1]s[i]一起解码,再加上s[i - 1]之前的字符的解码数;dp[i - 1]表示s[i]单独解码,再加上s[i]之前的字符的解码数)
  3. 对于当前数字字符s[i],若s[i - 1]s[i]衔接而成的数字不可解码,则s[i]单独解码:dp[i] = dp[i - 1]
  4. 需特殊考虑s[i] == '0’的问题 ('0’只可与它的前一位衔接解码,否则无法解码)
  • 若s[0] == ‘0’,则无法解码,return 0
  • 对于s[i],若s[i] == ‘0’,需判断s[i - 1]s[i]是否可解码:可解码则dp[i] = dp[i - 2];不可解码,则return 0
  • 对于s[i],若s[i] != ‘0’,则需判断s[i - 1]是否为’0’:若为’0’则s[i]只能单独解码,dp[i] = dp[i - 1];若不为’0’则可考虑s[i - 1]s[i]组合解码(如2、3中所述)
/** 
* @param {string} s 
* @return {number} 
*/
var numDecodings = function(s) {
         
    if(s[0] == '0') {
      // 0在首位,则不可能解码成功        
        return 0;    
    }    
    if(s.length == 1) {
      // 只有一位,且第一位不是0        
        return 1;    
    }    
    var dp = [];    
    var i = 0;
    // 先对dp[0]和dp[1]初始化    
    dp[0] = 1;    
    if(s[1] == '0') {
      // s[1]不可单独解码        
        if(s[0] == '1' || s[0] == '2') {
      // 只有'10' '20'可解码            
            dp[1] = 1;        
        }        
        else {
                 
            return 0;        
        }    
    }    
    else {
             
        if(Number(s[0] + s[1]) >= 1 && Number(s[0] + s[1]) <= 26) {
                 
            // s[0]s[1]可解码            
            dp[1] = 2; // 1. s[0]和s[1]分开解码;2. s[0]s[1]一起解码        
        }        
        else {
                 
            dp[1] = 1; // s[0]和s[1]分开解码        
        }    
    }
    
    for(i = 2; i < s.length; i++) {
             
        if(s[i] == '0') {
      // 出现0,则0必须和s[i - 1]能够一起解码            
            if(s[i - 1] == '1' || s[i - 1] == '2') {
                     
                dp[i] = dp[i - 2];            
            }            
            else {
                     
                return 0;            
            }        
        }        
        else {
      // 不为0            
            if(s[i - 1] == '0') {
      // 则s[i]只能单独解码                
                dp[i] = dp[i - 1];            
            }            
            else {
       // s[i]可能可以与s[i - 1]解码                
                if(Number(s[i - 1] + s[i]) >= 1 && Number(s[i - 1] + s[i]) <= 26) {
                         
                    // s[i - 1]s[i]可解码                    
                    dp[i] = dp[i - 1] + dp[i - 2];                
                }                
                else {
                         
                    dp[i] = dp[i - 1];                
                }            
            }        
        }    
    }    
    return dp[s.length - 1];
};

优化1
想法:

  1. dp[i]只与dp[i - 1]、dp[i - 2]有关,故:pre1保存dp[i - 1],pre2保存dp[i - 2],cur保存dp[i]
/** 
* @param {string} s 
* @return {number} 
*/
var numDecodings = function(s) {
         
    if(s[0] == '0') {
      // 0在首位,则不可能解码成功        
        return 0;    
    }    
    if(s.length == 1) {
      // 只有一位,且第一位不是0        
        return 1;    
    }    
    var pre1 = 0, pre2 = 0, cur = 0;    
    var i = 0;
    // 先对dp[0]和dp[1]初始化    
    pre2 = 1;    
    if(s[1] == '0') {
      // s[1]不可单独解码        
        if(s[0] == '1' || s[0] == '2') {
      // 只有'10' '20'可解码            
            pre1 = 1;        
        }        
        else {
                 
            return 0;        
        }    
    }    
    else {
             
        if(Number(s[0] + s[1]) >= 1 && Number(s[0] + s[1]) <= 26) {
                 
            // s[0]s[1]可解码            
            pre1 = 2; // 1. s[0]和s[1]分开解码;2. s[0]s[1]一起解码        
        }        
        else {
                 
            pre1 = 1; // s[0]和s[1]分开解码        
        }    
    }
    
    for(i = 2; i < s.length; i++) {
             
        if(s[i] == '0') {
      // 出现0,则0必须和s[i - 1]能够一起解码            
            if(s[i - 1] == '1' || s[i - 1] == '2') {
                     
                cur = pre2;            
            }            
            else {
                     
                return 0;            
            }        
        }        
        else {
      // 不为0            
            if(s[i - 1] == '0') {
      // 则s[i]只能单独解码                
                cur = pre1;            
            }            
            else {
       // s[i]可能可以与s[i - 1]解码                
                if(Number(s[i - 1] + s[i]) >= 1 && Number(s[i - 1] + s[i]) <= 26) {
                         // s[i - 1]s[i]可解码                    
                    cur = pre1 + pre2;                
                }                
                else {
                         
                    cur = pre1;                
                }            
            }        
        }        
        pre2 = pre1;        
        pre1 = cur;    
    }    
    return pre1;
};

优化2
看了题解,换了一种分类方式
想法:

  1. 若s[i] == ‘0’,则只有当s[i - 1] 为’1’或’2’时,s[i - 1]s[i]可共同解码:cur = pre2
  2. 若s[i] != ‘0’,则:
  • 若s[i - 1] == ‘1’,则s[i - 1]和s[i]可分开解码,也可一起解码:cur = pre1 + pre2
  • 若s[i - 1] == ‘2’ && s[i] >= ‘1’ && s[i] <= ‘6’,则s[i - 1]和s[i]可分开解码,也可一起解码:cur = pre1 + pre2
  • 以上两种情况都不满足,则只有s[i]单独解码:cur = pre1
    注:pre1为以s[i - 1]字符结尾的串的解码方法总数;pre2为以s[i - 2]字符结尾的串的解码方法总数;cur为以s[i]字符结尾的串的解码方法总数
/** 
* @param {string} s 
* @return {number} 
*/
var numDecodings = function(s) {
         
    if(s[0] == '0') {
      // 0在首位,则不可能解码成功        
        return 0;    
    }    
    var pre1 = 0, pre2 = 0, cur = 0;    
    var i = 0;    
    pre1 = pre2 = 1;    
    for(i = 1; i < s.length; i++) {
      // 从第二位数字开始        
        if(s[i] == '0') {
      // 出现0,则0必须和s[i - 1]能够一起解码            
            if(s[i - 1] == '1' || s[i - 1] == '2') {
                     
                cur = pre2;            
            }            
            else {
                     
                return 0;            
            }        
        }        
        else {
      // 不为0            
            if(s[i - 1] == '1') {
                      
                cur = pre1 + pre2;            
            }            
            else if(s[i - 1] == '2' && (s[i] >= '1' && s[i] <= '6')){
                      
                cur = pre1 + pre2;            
            }            
            else {
                     
                cur = pre1;            
            }        
        }        
        pre2 = pre1;        
        pre1 = cur;    
    }    
    return pre1;
};

你可能感兴趣的:(LeetCode,leetcode,js,动态规划)