LeetCode第[91]題(Java):Decode Ways(解碼方法數)


題目:解碼方法數

難度:Medium

題目內容

A message containing letters from A-Z is being encoded to numbers using the following mapping:

'A' -> 1
'B' -> 2
...
'Z' -> 26

Given a non-empty string containing only digits, determine the total number of ways to decode it.

翻譯

一個包含A-Z字母的消息被編碼成數字,使用以下映射:

“A” - > 1

“B”- > 2

……

“Z”- > 26

給定一個包含數字的非空字符串,確定解碼它的總方法數。

 

我的思路:一開始想用遞歸但是邊界問題太多,就放棄了。

      single 從0開始(每個數組單獨解碼),count從1開始,如果s[i-1]s[i]二者組成的數字在(0,26 ] 范圍內,那就count+;

      且遇見0的時候,一開始的單獨編碼就不存在了,且少了一次組合的機會,例如【110】 中【11】和【0】不能組合

        所以此時 single = 0;count - 1

我的代碼

 1     public int numDecodings(String s) {
 2         if (s.isEmpty() || s.charAt(0) == '0')
 3             return 0;
 4         
 5         int count = 0;
 6         int single = 1;
 7         for (int i = 1; i < s.length(); i++) {
 8             if (s.charAt(i) == '0'){
 9                 count = s.length() > 2 ? count-1 : count;
10                 single = 0;
11             }
12             int x = Integer.parseInt(s.substring(i-1, i+1));
13             if ( x<= 26 && x > 0) {
14                 count += 1;
15             }
16         }
17         return (count + single) > 0 ? (count + single) : 0;
18     }

結果214 / 258 test cases passed.

Input:"1212"
Output:4
Expected:5

編碼過程中的問題

1、最初 single 和 count 沒有分開計算;

2、第9行,當只有兩個的時候,此時count 不需要 -1 ,例如【10】;

3、這個思路還是有問題的,例如【1212】中少計算了【12】【12】這個組合

 

答案代碼

 1 public class Solution {
 2     public int numDecodings(String s) {
 3         int n = s.length();
 4         if (n == 0) return 0;
 5         
 6         int[] memo = new int[n+1];
 7         memo[n]  = 1;
 8         memo[n-1] = s.charAt(n-1) != '0' ? 1 : 0;
 9         
10         for (int i = n - 2; i >= 0; i--)
11             if (s.charAt(i) == '0') continue;
12             else memo[i] = (Integer.parseInt(s.substring(i,i+2))<=26) ? memo[i+1]+memo[i+2] : memo[i+1];
13         
14         return memo[0];
15     }
16 }

答案思路

假設所有的數字都有效,且左右兩兩相鄰數之間也有效(1到26),那么有如下規律

   numDecodings(s) = numDecodings(s.substring(1)) + numDecodings(s.substring(2)) --------------------------------------------------式(1)

規律顯而易見,斐波那契數列。不過是反過來的(從字符串后面往前)

當然,那只是假設,也要考慮特殊情況:

使用一個數組(大小為len+1)從后往前記錄對應的數字“出現”后解碼數的增量

1、當前指針所指字符為0

  此時此字符無法解碼,所以式(1)中的前者就只能為0,后者也為0

  例如【023】,substring(1)——【0】|【23】,截掉的【0】不能解析,所以此組合無效

         substring(2)——【02】|【3】,截掉的【02】不能解析,所以此組合無效

  所以0數字出現后,解碼數的增量為0。

2、當前字符的值是有效的(大於0),但是當前字符與右邊字符組合的數字無效(大於26)

  相當於式(1)中的后者=0

  例如【3212】,substring(1)——【3】|【212】,截掉的【3】能解析,所以其值為【212】的解碼數

         substring(2)——【32】|【12】,截掉的【32】不能解析,所以此組合無效\

遞歸實現:

 1     public int numDecodings(String s) {
 2         if (s.isEmpty()) {
 3             return 1;
 4         }
 5         
 6         if (s.charAt(0) == '0') {
 7             return 0;
 8         } 
 9         
10         if (s.length() == 1)
11             return 1;
12             
13         int sub1 = numDecodings(s.substring(1));
14         int sub2 = 0;
15         
16         if (Integer.parseInt(s.substring(0,2)) <= 26) {
17             sub2 = numDecodings(s.substring(2));
18         }
19         return sub1 + sub2;
20     }

此方法會在最后幾個用例(很長)運行超時。

所以答案采用了迭代的方式進行。

優化:既然是斐波納數列,那么就能使用雙值迭代的方式取代用一個數組進行記錄

 1     public int numDecodings(String s) {
 2         if (s.isEmpty() || s.charAt(0) == '0') {
 3             return 0;
 4         }
 5         int sub1 = 1;
 6         int sub2 = 1;
 7         for (int i = s.length() - 2; i > -1; i--) {
 8             if (s.charAt(i+1) == '0') {
 9                 sub1 = 0;
10             }
11             if (Integer.parseInt(s.substring(i,i+2)) <= 26) {
12                 sub1 = sub1 + sub2;
13                 sub2 = sub1 - sub2;
14             } else {
15                 sub2 = sub1;
16             }
17         }
18         return sub1;
19     }

第11行其實還可以使用字符進行判斷以降低時間和空間復雜度:

   s.charAt(i) == '1' || s.charAt(i) == '2' && s.charAt(i+1) - '0' <= 6 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM