Idiot-maker

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

https://leetcode.com/problems/decode-ways/

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

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

Given an decoded message containing digits, determine the total number of ways to decode it.

For example,
Given decoded message "12", it could be decoded as "AB" (1 2) or "L" (12).

The number of ways decoding "12" is 2.

解题思路:

根据“求解数量用dp,求解集合用dfs”的经验,这题应该用dp来做。

这题有点像走楼梯的题目,定义子状态dp[i]为s.substring(0, i + 1)的decode可能数量。

我们先不考虑s里面含0的情况。如果i和i-1两个字符组成的数字大于27,那么加上i后,不可能有新的decode方法,dp[i]=dp[i - 1]。否则它大于0且小于27,代表还能有一种decode可能,那么dp[i] = dp[i - 1] + dp[i - 2]。

问题是,0的出现使得这道题目比较麻烦。我的方法是,分别考虑i - 1和i是不是0,分四种情况。

1. i - 1 == 0。

1.1 如果i == 0,连续两个0,不可能被decode,直接返回0。

1.2 如果i != 0,dp[i] = dp[i - 1]。

2. i - 1 != 0

2.1 如果i != 0,套用上面的思路。

2.2 如果i == 0,在i - 1 == 1或者i - 1== 2的情况下,dp[i] = dp[i - 2]。否则,i这个地方的0无法和前面一个字符结合,作为从i往后出现的第一个0,也无法被decode,所以直接返回0。

public class Solution {
    public int numDecodings(String s) {
        int n = s.length();
        if(n == 0) {
            return 0;
        }
        if(s.indexOf("0") == 0) {
            return 0;
        }
        
        int[] dp = new int[n];
        dp[0] = 1;
        
        for(int i = 1; i < n; i++) {
            if(s.charAt(i - 1) == '0') {
                if(s.charAt(i) != '0') {
                    dp[i] = dp[i - 1];
                } else {
                    return 0;
                }
            }else {
                if(s.charAt(i) != '0') {
                    if(Integer.valueOf(s.substring(i - 1, i + 1)) <= 26) {
                        if(i - 2 < 0) {
                            dp[i] = 2;
                        }else {
                            dp[i] = dp[i - 1] + dp[i - 2];
                        }
                    } else {
                        dp[i] = dp[i - 1];
                    }
                } else {
                    if(s.charAt(i - 1) == '1' || s.charAt(i - 1) == '2') {
                        if(i - 2 < 0) {
                            dp[i] = 1;
                        }else {
                            dp[i] = dp[i - 2];
                        }
                    } else {
                        return 0;
                    }
                }
            }
        }
        return dp[n - 1];
    }
}

 //20181003

如果i位是0,则它必须要和前一个digit结合,且前一个digit必须是1或者1。一旦结合了,dp[i]就只能等于dp[i] - 2。比如“110”.

如果i不是0,如果它的前一位是1,则他可以和前一位结合,也可以不结合。所以就有两种decode的可能,那么dp[i]=dp[i-1] + dp[i-2]。

如果它的前一位是2,则只有当它是1-6的时候才能和前一位结合,当然也可以不结合。如果大于6,就只能不结合了。

当然,这里所有的情况都还要考虑i==1的情况,因为我们是往前看两位。

class Solution {
    public int numDecodings(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }

        int[] dp = new int[s.length()];
        if (s.charAt(0) == '0') {
            return 0;
        }
        dp[0] = 1;
        
        for (int i = 1; i < s.length(); i++) {
            if (s.charAt(i) == '0') {
                if (s.charAt(i - 1) == '1' || s.charAt(i - 1) == '2') {
                    dp[i] = i == 1 ? 1 : dp[i - 2];
                } else {
                    return 0;
                }                
            } else {
                if (s.charAt(i - 1) == '1') {
                    dp[i] = i == 1 ? 2 : dp[i - 2] + dp[i - 1];
                } else if (s.charAt(i - 1) == '2') {
                    if (s.charAt(i) < '7') {
                        dp[i] = i == 1 ? 2 : dp[i - 2] + dp[i - 1];
                    } else if (s.charAt(i) > '6') {
                        dp[i] = dp[i - 1];
                    }
                } else {
                    dp[i] = dp[i - 1];
                }
            }
            
        }
        return dp[dp.length - 1];
    }
}

 

posted on 2015-04-18 23:42  NickyYe  阅读(200)  评论(0编辑  收藏  举报