# 91. Decode Ways ## me, wrong strategy, fail ### try 1, fail ```python= class Solution: def numDecodings(self, s: str) -> int: ints = int(s) if ints == 0: return 0 if 1 <= ints <= 10: return 1 if 11 <= ints <= 19: return 2 if ints == 10: return 1 if 21 <= ints <= 26: return 2 if 27 <= ints <= 99: return 1 return self.numDecodings(s[0:2]) * self.numDecodings(s[2:]) + self.numDecodings(s[0]) * self.numDecodings(s[1:]) ``` :::danger Wrong Answer Input "226" Output 4 Expected 3 ::: I double count the `2 | 2 | 6` ### try 2, fail ```python= class Solution: def numDecodings(self, s: str) -> int: ints = int(s) if ints == 0: return 0 if 1 <= ints <= 10: return 1 if 11 <= ints <= 19: return 2 if ints == 10: return 1 if 21 <= ints <= 26: return 2 if 27 <= ints <= 99: return 1 return self.numDecodings(s[0:2]) * self.numDecodings(s[2:]) + self.numDecodings(s[0]) * self.numDecodings(s[1:]) - self.numDecodings(s[0]) * self.numDecodings(s[1]) * self.numDecodings(s[2:]) ``` :::danger Wrong Answer Input "01" Output 1 Expected 0 ::: `"01"` is going the same as `"1"`, which is wrong ### try 3, fail ```python= class Solution: def numDecodings(self, s: str) -> int: if len(s) == 2 and s[0] == "0": return 0 ints = int(s) if ints == 0: return 0 if 1 <= ints <= 10: return 1 if 11 <= ints <= 19: return 2 if ints == 10: return 1 if 21 <= ints <= 26: return 2 if 27 <= ints <= 99: return 1 return self.numDecodings(s[0:2]) * self.numDecodings(s[2:]) + self.numDecodings(s[0]) * self.numDecodings(s[1:]) - self.numDecodings(s[0]) * self.numDecodings(s[1]) * self.numDecodings(s[2:]) ``` :::danger Wrong Answer Input "012" Output 2 Expected 0 ::: ### try 4, fail ```python= class Solution: def numDecodings(self, s: str) -> int: if s[0] == "0": return 0 ints = int(s) if ints == 0: return 0 if 1 <= ints <= 10: return 1 if 11 <= ints <= 19: return 2 if ints == 10: return 1 if 21 <= ints <= 26: return 2 if 27 <= ints <= 99: return 1 return self.numDecodings(s[0:2]) * self.numDecodings(s[2:]) + self.numDecodings(s[0]) * self.numDecodings(s[1:]) - self.numDecodings(s[0]) * self.numDecodings(s[1]) * self.numDecodings(s[2:]) ``` :::danger Wrong Answer Input "230" Output 1 Expected 0 ::: ### try 5, fail ```python= class Solution: def numDecodings(self, s: str) -> int: if s[0] == "0": return 0 ints = int(s) if ints == 0: return 0 if 1 <= ints <= 10: return 1 if 11 <= ints <= 19: return 2 if ints == 10: return 1 if 21 <= ints <= 26: return 2 if ints == 30 or ints == 40 or ints == 50 or ints == 60 or ints == 70 or ints == 80 or ints == 90: return 0 if 27 <= ints <= 99: return 1 return self.numDecodings(s[0:2]) * self.numDecodings(s[2:]) + self.numDecodings(s[0]) * self.numDecodings(s[1:]) - self.numDecodings(s[0]) * self.numDecodings(s[1]) * self.numDecodings(s[2:]) ``` :::danger Runtime Error Details Playground Debug RecursionError: maximum recursion depth exceeded while calling a Python object Line 3 in numDecodings (Solution.py) [Previous line repeated 996 more times] Line 14 in numDecodings (Solution.py) Line 14 in numDecodings (Solution.py) Line 14 in numDecodings (Solution.py) stdout 12120 12 120 12 0 1 20 20 20 20 20 20 20 ... 49910 more lines Last executed input "12120" ::: It is a typo. Should be `if ints == 10: return 1` Not `if ints == 20: return 1` ### try 6, fail ```python= class Solution: def numDecodings(self, s: str) -> int: print(s) if s[0] == "0": return 0 ints = int(s) if ints == 0: return 0 if 1 <= ints <= 10: return 1 if 11 <= ints <= 19: return 2 if ints == 20: return 1 if 21 <= ints <= 26: return 2 if ints == 30 or ints == 40 or ints == 50 or ints == 60 or ints == 70 or ints == 80 or ints == 90: return 0 if 27 <= ints <= 99: return 1 return self.numDecodings(s[0:2]) * self.numDecodings(s[2:]) + self.numDecodings(s[0]) * self.numDecodings(s[1:]) - self.numDecodings(s[0]) * self.numDecodings(s[1]) * self.numDecodings(s[2:]) ``` :::danger Time Limit Exceeded Last executed input "6065812287883668764831544958683283296479682877898293612168136334983851946827579555449329483852397155" ::: ### try 7, fail ```python= class Solution: def numDecodings(self, s: str) -> int: if s[0] == "0": return 0 ints = int(s) if ints == 0: return 0 if 1 <= ints <= 10: return 1 if 11 <= ints <= 19: return 2 if ints == 20: return 1 if 21 <= ints <= 26: return 2 if ints == 30 or ints == 40 or ints == 50 or ints == 60 or ints == 70 or ints == 80 or ints == 90: return 0 if 27 <= ints <= 99: return 1 return (self.numDecodings(s[0:2]) - self.numDecodings(s[0])*self.numDecodings(s[1]))*self.numDecodings(s[2:]) + self.numDecodings(s[0])*self.numDecodings(s[1:]) ``` :::danger Time Limit Exceeded Last executed input "6065812287883668764831544958683283296479682877898293612168136334983851946827579555449329483852397155" ::: :::info I shoud have memory I should DP ::: ## dp ### try 1, fail ```python= class Solution: def numDecodings(self, s: str) -> int: if s[0] == "0": return 0 # the first char is not '0' n = len(s) dp = [0] * n # 0 ~ n-1 dp[0] = 1 for i in range(1, n): if s[i] != '0': dp[i] = dp[i-1] if 10 <= int(s[i-1:i+1]) <= 26: # i-1 ~ i dp[i] += 1 return dp[-1] ``` :::danger Wrong Answer Input "12120" Output 1 Expected 3 ::: ### try 2, success, use `if` in `for` to deal with the special case of counting `s[0:3]` ```python= def numDecodings(self, s: str) -> int: if s[0] == "0": return 0 # the first char is not '0' n = len(s) dp = [0] * n # 0 ~ n-1 dp[0] = 1 for i in range(1, n): print(dp) if s[i] != '0': dp[i] += dp[i-1] if 10 <= int(s[i-1:i+1]) <= 26: # i-1 ~ i # to avoid access of dp[-1] if i == 1 : dp[i] += 1 else: dp[i] += dp[i-2] print(dp) return dp[-1] ``` ### try 3, success, shift dp chart to avoid `dp[0:3]` ```python= def numDecodings(self, s: str) -> int: if s[0] == "0": # return 0 # the first char is not '0' n = len(s) dp = [0] * (n+1) # 0 ~ n # we shift the dp chart from the input s by 1 # the possible decode way of s[0:a+1] is stroe at dp[a+1] dp[0] = 1 # only for counting the 2-digit at s[0~1], dp[1] = 1 # for the first char is not '0', there is one decode way for i in range(2, n+1): # if the 1-digit is 1~9 then the previous count is OK to use if s[i-1] != '0': dp[i] += dp[i-1] # if the 2-digit is 10~26, then the previous count is OK to use if 10 <= int(s[i-2:i]) <= 26: dp[i] += dp[i-2] return dp[n] ```