[LeetCode 91] Decode Ways
A message containing letters from A-Z
is 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.
Given encoded message 12
, it could be decoded as AB
(1 2) or L
(12).
The number of ways decoding 12
is 2.
Solution 1. DFS Recursive Solution
From the given mapping, we know that the decoding must be done in the following way.
1. single character decode: must not be '0', can be from '1' to '9'
2. two characters decode: must be from '10' to '26'
We can derive a recursive formula that solves this problem.
f(i) = f(i - 1) + f(i - 2) if s[i] is not '0' and s[i - 1, i] is between 10 and 26;
f(i) = f(i - 1) if s[i] is not '0' but s[i - 1, i] is outside of [10, 26];
f(i) = f(i - 2) if s[i] is '0' but s[i - 1, i] is between 10 and 26;
f(i) = 0 if s[i] is '0' and s[i - 1, i] is outside of [10, 26];
We can easily write the following dfs recursive solution. But it is very inefficient as we repeatedly
calculate the same subproblems, just like the problems Climbing Stairs and Fibonacci. The only
difference between this problem and climbing stairs is that this problem requires a condition check
when computing subproblems, since not every one or two characters divide meet thedecode mapping
requirement.
1 public class Solution { 2 public int numDecodings(String s) { 3 if(s == null || s.length() == 0){ 4 return 0; 5 } 6 return dfs(s, s.length() - 1); 7 } 8 private int dfs(String s, int end){ 9 //base case of length 1 10 if(end == 0){ 11 if(s.charAt(end) != '0'){ 12 return 1; 13 } 14 else{ 15 return 0; 16 } 17 } 18 //base case of length 2 19 if(end == 1){ 20 int ways = 0; 21 if(s.charAt(end - 1) == '0'){ 22 return 0; 23 } 24 if(s.charAt(end) != '0'){ 25 ways++; 26 } 27 int num = (s.charAt(end - 1) - '0') * 10 + (s.charAt(end) - '0'); 28 if(num <= 26){ 29 ways++; 30 } 31 return ways; 32 } 33 int ways = 0; 34 if(s.charAt(end) != '0'){ 35 ways += dfs(s, end - 1); 36 } 37 int num = (s.charAt(end - 1) - '0') * 10 + (s.charAt(end) - '0'); 38 if(s.charAt(end - 1) != '0' && num <= 26){ 39 ways += dfs(s, end - 2); 40 } 41 return ways; 42 } 43 }
Solution 2. Dynamic Programming
To avoid overlapping subproblems computation, we use dynamic programming.
State:
states[i]: the total number of ways to decode the first i characters
Function:
states[i] += states[i - 1] if s[i - 1] != '0';
states[i] += states[i - 2] if s[i - 2, i - 1] is between 10 and 26;
if states[i] == 0 after the above two calculation, return 0 as it is impossible to decode
the input string according to the given mapping rule.
Initialization:
states[0] = 1; when there is no character, no decoding is needed, so we have 1 way of decoding it, which is do nothing.
states[1] = (s.charAt(0) == '0' ? 0 : 1);
states[i] = 0 for i >= 2;
Answer:
states[s.length]; if any states[i] for i != 0 is 0 after calculation, we can simply return 0 as
it is impossible to decode.
1 public class Solution { 2 public int numDecodings(String s) { 3 if(s == null || s.length() == 0){ 4 return 0; 5 } 6 int n = s.length(); 7 int[] states = new int[n + 1]; 8 states[0] = 1; 9 states[1] = (s.charAt(0) == '0' ? 0 : 1); 10 if(states[1] == 0){ 11 return 0; 12 } 13 for(int i = 2; i <= n; i++){ 14 states[i] = 0; 15 } 16 for(int i = 2; i <= n; i++){ 17 int num = (s.charAt(i - 2) - '0') * 10 + (s.charAt(i - 1) - '0'); 18 if(s.charAt(i - 1) != '0'){ 19 states[i] += states[i - 1]; 20 } 21 if(s.charAt(i - 2) != '0' && num <= 26){ 22 states[i] += states[i - 2]; 23 } 24 if(states[i] == 0){ 25 return 0; 26 } 27 } 28 return states[n]; 29 } 30 }
Related Problems
Climbing Stairs
Climbing Stairs II
Wildcard Matching
Regular Expression Matching