1. 程式人生 > >數字字串對應解碼方式

數字字串對應解碼方式

package leetcode;
/*A message containing letters fromA-Zis being encoded to numbers using the following mapping:

'A' -> 1
'B' -> 2
...
'Z' -> 26
Given an encoded message containing digits, determine the total number of ways to decode it.

For example,
Given encoded message"12", it could be decoded as"AB"(1 2) or"L"(12).

The number of ways decoding"12"is 2.*/
public class Decode_ways {
      public static void main(String[] args) {
        System.out.println(numDecodings("17"));
    }
      
   //我自己的方法是利用簡單粗暴的遞迴,但是那樣時間複雜度太高,無法通過,所以利用了記憶化搜尋,把子問題的結果進行儲存,以免重複計算
      public static int numDecodings(String s) {

           int [] memo =new int[s.length()+1];     //定義陣列,儲存已解決出來的子問題
           char[] c = s.toCharArray();
           int N = c.length;
           if(N == 0 )                            //字串長度為0,則直接返回0
               return 0 ;
           memo[0] = numDecodings(c,0,N-1,memo);  //對應方法進行求解
         return memo[0];
          
      }


    private static int numDecodings(char[] c, int i, int n, int[] memo) {
        // TODO Auto-generated method stub
        if(i == n && c[i] == '0')                      //剩下最後一個字元為0,表示這種劃分方式有問題,所以返回為0
            return 0;
        if(i >= n )                                    //當已經到結尾了,證明是一種劃分方式
            memo[i] = 1;
        if(memo[i] != 0) {                             //當這個子問題已經解決過,則直接返回結果
            return memo[i];
        }
        
        if(c[i]<='0' )                                //字元不符合要求,則此種劃分方式有問題,所以返回為0
            memo[i] = 0;
        else if((c[i]=='2' && c[i+1]<='6') || (c[i+1]<='9'&& c[i]=='1')) {    //表示此字元單獨為一個,和下一個字符合並在一起都可以
            memo[i] = numDecodings(c, i+1, n, memo) + numDecodings(c, i+2, n, memo); //所以為兩種方式的劃分結果之和
        }
        else if(c[i]>='1'&& c[i]<='2'&& c[i+1]=='0') {                  //表示若此字元單獨劃分不可以,只能和下一個字元組合
            memo[i] = numDecodings(c, i+2, n, memo);
        }else {
            memo[i] = numDecodings(c, i+1, n, memo);                   //表示此字元必須單獨劃分
        }
        return memo[i];         //返回此子問題的結果
    }
}
//以下是牛客網上的最優解法
//成功把自上向下的解決辦法,用自下向上來解
/*public int numDecodings(String s) {
    //解題思路:
    //基本是斐波拉契數列dp[i]=dp[i-1]+dp[i-2]
    //dp[i]表示s[0-(i-1)]的解法的個數
    //dp[i-1]表示單獨加入新的數字,dp[i-2]表示和前面一個數字湊
    //http://www.cnblogs.com/grandyang/p/4313384.html
    if(s.length() == 0 || s == null || (s.length() > 1 && s.charAt(0)== '0')){
        return 0;
    }
    int[] dp = new int[s.length()+1];
    dp[0] = 1;               //這個佔用位並沒有實際意義,只是為了使程式碼更順暢
    for(int i = 1; i < dp.length; i++){
            //前面一個字元不是'0'則dp[i]至少等於dp[i-1]
            if(s.charAt(i-1) == '0'){
                dp[i] = 0;
            }else{
                dp[i] = dp[i-1];
            }
            //判斷前一個字元和當前字元是不是可以湊
            if(( i > 1 && s.charAt(i-1)<= '6' && s.charAt(i-2) =='2') || ( i > 1 && s.charAt(i-2) == '1' ) ){
                dp[i] += dp[i-2];
            }
    }
     
    return dp[s.length()];*/    //因為dp【0】被佔用,所以dp【i】對應就表示i長度的字串方法