您的位置:首页 > 其它

[LeetCode#91]Decode Ways

2015-08-27 09:56 211 查看
Problem:

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.

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.

Analysis:

Note the transitional function!!!
At first glance, it could be solved through recursive call. But we only care about the total count!!! Why we must follow that routinue.
The difference here are only: count the present digit as a character, or count two digits as a character. For all chacter, we should ask us the same question. since there are only two possible situations, why not we use dynamic programming for it.
The range of two digits in this problem is '00' - '99', we could intepret those two digits separately or together.
Suppose res[i] represents the sequences count from 0 to i.
1.'00'
res[i] = 0, since '00' is invalid and '0' is invalid.

2. '01' - '09'
res[i] = res[i-1], must be sperated.

3. '10', '20'
res[i] = res[i-2], the new added character must be combined with '1' or '2'

4. '11-19', '21 - 26'
res[i] = res[i-2] + res[i-1]

5. '27-99' not include *0
res[i] = res[i-1]

----------------------------------------------------
1.'00'
res[i] = 0, since '00' is invalid and '0' is invalid.
----------------------------------------------------
6. *0 (exclude '10', '20')
res[i] = 0

Do you think the above analysis is too ugly and complex?
When a '0' appears, we need to tackle so many different cases. The related program must be very ugly too!

Can we find a way to avoid the complex checking?
Yes!!!!
Why not do the dynamic prgramming from right to left?

'0*' must be invalid for both cases, we can directly ignore it.
'01'. '0'is invalid, and '01' is also invalid.
for (int i = len-1; i >= 0; i--) {
if (s.charAt(i) != '0') {
...
}

If s.charAt(i) is not equal to '0',
1. it must could be separately intepreted '1' .. '9' are valid.
2. it might be valid for inteprrting together. '11' _ '26' are valid. (note: no '0' start)
if (s.charAt(i) != '0') {
dp[i] = dp[i+1];
if (i < len-1 && Integer.parseInt(s.substring(i, i+2)) <= 26)
dp[i] += dp[i+2];
}

How easy of this solution, right?
Skills:
How initiate the value for first intepreted character or 'two character'.
Can you use
int[] dp = new int[len];
dp[0] = 1
Absolutely no!!!, what if the last character is '0'. like '20'
And it would break the elegant code structure.

How about use a extra element?
int[] dp = new int[len+1];
dp[len] = 1;

1. last character
if the last element is '0'.
dp[len-1] still equal to 0
if the last element is not '0'.
dp[i] = dp[i+1];

2. last two character
if the second to last element is '0'
dp[len-1] still equal to 0
if the second to last element is not '0' and in the valid range '11 - 26'
dp[i] += dp[i+2] (1);

What a great skill!!!
How to give the initial value for two case through a additional element, while keep the elegant code structure at the same time.


Solution:

public class Solution {
public int numDecodings(String s) {
if (s == null || s.length() == 0)
return 0;
int len = s.length();
int[] dp = new int[len+1];
dp[len] = 1;
for (int i = len-1; i >= 0; i--) {
if (s.charAt(i) != '0') {
dp[i] = dp[i+1];
if (i < len-1 && Integer.parseInt(s.substring(i, i+2)) <= 26)
dp[i] += dp[i+2];
}
}
return dp[0];
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: