【两次过】【序列型】Lintcode 512. 解码方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/majichen95/article/details/83211195

有一个消息包含A-Z通过以下规则编码

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

现在给你一个加密过后的消息,问有几种解码的方式

样例

给你的消息为12,有两种方式解码 AB(12) 或者 L(12). 所以返回 2


解题思路:

序列型动态规划。对于序列计数型问题,一般dp[i]代表前i个,而不包括第i个,所以新建dp数组,一般需要多建一个。

最后一步

一定是一个字母A or B ... or Z。所以最后一步要么是一个数字组成的字母,要么是两个数字组成的字母。

根据最后一步,可推出子问题

子问题

要求数字串前i个字符的解码方式,就需要知道前i-1和前i-2个字符的解码方式。

确定状态

设dp[i]为数字串前i个字符的解码方式数

则状态方程:dp[i] = dp[i-1] + dp[i-2]

初始条件与边界条件:

dp[0] = 1

数字串S[i-1]需对应一个字母,即:S[i-1]在[1-9]之间

数字串S[i-2][i-1]组成的两个数字需对应一个字母,即:S[i-2][i-1]在[10-26]之间

public class Solution {
    /**
     * @param s: a string,  encoded message
     * @return: an integer, the number of ways decoding
     */
    public int numDecodings(String s) {
        // write your code here
        if(s == null || s.length() == 0)
            return 0;
        
        char[] arr = s.toCharArray();
        int n = arr.length;
        
        int[] dp = new int[n+1];//dp[i]为数字串前i个字符的解码方式数,不包括i
        
        //初始条件
        dp[0] = 1;
        if(arr[0] == '0')
            dp[1] = 0;
        else
            dp[1] = 1;
        
        for(int i=2; i<dp.length; i++){
            //倒数第一个字符必须为[1,9]之间
            if(arr[i-1] == '0')
                dp[i-1] = 0;
            
            //倒数两个字符必须在[10-26]之间
            String ss = "" + arr[i-2] + arr[i-1];
            int temp = Integer.valueOf(ss);
            if(temp > 26 || temp == 0)
                dp[i-2] = 0;
            
            //状态方程
            dp[i] = dp[i-1] + dp[i-2];
        }
        
        return dp[n];
    }
}

猜你喜欢

转载自blog.csdn.net/majichen95/article/details/83211195