DecodeWays-L91
#medium
Information
- Link: [https://neetcode.io/problems/decode-ways]
- Difficulty: [Medium]
- Date:
- Solution:https://youtu.be/6aEyTjOwlJU
Approach & Code
Approach 1: Recursive Brute Force using tree
- This approach is a recursive brute force approach which is based on the tree based on the tree based approach.
- For every character it can either behave as single or two digits within some contraints.
- Also this is a recursive approach where each it process the whole of string by taking each char once in combination of one or two digits.
- The two char combination is checked for constraints of :
- no 0 as its first character .
- 1 place character should be less than 7 if the 0th character is 2. ( This is to check characters from 1 to 26)
- If the no of character is only one then it has reached to the end of
the string with taking each characters under consideration.
- So one, 1 is returned for that branch of tree.
- So for each complete branch only one is added.
class Solution: def numDecodings(self, s: str) -> int: def dfs(i): if i==len(s): return 1 if s[0] =='0': return 0 res = dfs(i+1 if(i<len(s)-1): if(s[i]=='1' or s[i]=='2' and s[i+1]<'7'): res+=dfs(i+2) return res return dfs(0) n = "12345" eval = Solution() out1 = eval.numDecodings(n) print(out1)
Problem Complexity:
- Time Complexity: O(2n) as it branches out on every character and it can have 2 branches on every char. And it needs to create 2n branches and run over all the combination to complete the problem
- Space Complexity: O(n)
Key Takeaway / Learning:
- Recursion
- Tree Approach (need to develop more intuition)
Approach 2: Dynamic Approach:
- This is using the Dynamic Programming Approach
- This creates a memory to save the already calcualted value so that
recalculation is avoided .
- This is done by keeping a dictionalry named dp.
- First the value of dp is initialized by the len(s) value which is not a normal case as len(s) char doesnot exits in the string.
- Then in the tree (dfs) it will look for the value for i in dp, if it is already present then no need to calculate it.
- Then if it is not present then check for if it is 0, as it is the invalid case .
- If both the conditions passes then it will look for case with single digit.
- Also after checking for the double digit and its contraints(no first char to be 0 and no second char to be grater than 6), it calculates for 2 digits too.
- And all the results are accumulated in res variable.
- The program starts from 0th digit.
class Solution: def numDecodings(self, s: str) -> int: dp = {len(s):1} def dfs(i): # print("temp ->",i,":",dp) if(i in dp): print("dp->",i,"->",dp[i]) return dp[i] if (s[i]=="0"): return 0 print("s[",i,"]->",s[i]) res = dfs(i+1) if(i+1<len(s)) and(s[i]=="1" or (s[i]=="2" and s[i+1] in "0123456")): print("Here->",s[i],",",s[i+1]) res += dfs(i+2) dp[i] = res print("temp ->",i,":",dp) return res return dfs(0) n = "12345234" eval = Solution(); out1 = eval.numDecodings(n) print("Result",out1)
s[ 0 ]-> 1
s[ 1 ]-> 2
s[ 2 ]-> 3
s[ 3 ]-> 4
s[ 4 ]-> 5
s[ 5 ]-> 2
s[ 6 ]-> 3
s[ 7 ]-> 4
dp-> 8 -> 1
temp -> 7 : {8: 1, 7: 1}
temp -> 6 : {8: 1, 7: 1, 6: 1}
Here-> 2 , 3
dp-> 7 -> 1
temp -> 5 : {8: 1, 7: 1, 6: 1, 5: 2}
temp -> 4 : {8: 1, 7: 1, 6: 1, 5: 2, 4: 2}
temp -> 3 : {8: 1, 7: 1, 6: 1, 5: 2, 4: 2, 3: 2}
temp -> 2 : {8: 1, 7: 1, 6: 1, 5: 2, 4: 2, 3: 2, 2: 2}
Here-> 2 , 3
dp-> 3 -> 2
temp -> 1 : {8: 1, 7: 1, 6: 1, 5: 2, 4: 2, 3: 2, 2: 2, 1: 4}
Here-> 1 , 2
dp-> 2 -> 2
temp -> 0 : {8: 1, 7: 1, 6: 1, 5: 2, 4: 2, 3: 2, 2: 2, 1: 4, 0: 6}
Result 6
Problem Complexity:
- Time Complexity: O(n) as it will pass through the list once and uses the calculation done in previous steps.
- Space Complexity: O(n) as it will store the key value for all the indexes of the string+1.
Key TakeWay / Learning:
- Dynamic Programming
- Memoization
- Recursion
Approach 3: Dynamic Programming (Bottom Up Approach):
- This is a variant of dynamic programming a bit different from the above implementation from the second approach.
- Here it starts from the last entry and get to the first char.
class Solution: def numDecodings(self, s: str) -> int: dp = {len(s):1} for i in range(len(s)-1, -1, -1): if(s[i]=='0'): dp[i]= 0 else: dp[i] = dp[i+1] if((i+1)<len(s) and (s[i] == '1' or (s[i]=='2' and s[i+1] in '0123456'))): dp[i] += dp[i+2] return dp[0] n='1222' eval = Solution() out1 = eval.numDecodings(n) print(out1)
5
Problem Complexity:
- Time : O(n)
- Space: O(n)
Key Takeway:
- Dynamic Programming
- Bottom Up Approach