DP动态规划专题一 :LeetCode 91. Decode Ways

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 a non-empty string containing only digits, determine the total number of ways to decode it.

Example 1:

Input: "12"
Output: 2
Explanation: It could be decoded as "AB" (1 2) or "L" (12).
Example 2:

Input: "226"
Output: 3
Explanation: It could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).

解决动态规划问题最主要的就是得到动态规划的公式,思路还是用数学归纳法,先假设0~n-1已经完成,看看怎么通过0 - n-1来推n,这个时候,如果n的答案至少依赖于n-1和n-2的答案时,数据结构就成了图,除了分叉还有交叉,这时候就可以用hashmap保存0 - n-1的答案,每次在后面需要时就可以直接得到。而hashmap又可以简化为数组的伪哈希表来存放答案。这就是为什么我们会看到有些题是用数组来记录的,好处在于数组可以bulk load,优化时间。这道题的关键在于,怎么更新这个可能的个数,先假设不存在0,那么就需要判断i与i-1的关系,如果i-1和i构成的数字小于等于26,那么可能的个数是dp[i] = dp[i-1] + dp[i-2], 因为两个数字可以结合一起decode,也可以分开decode;如果大于26,只能分开decode,dp[i] = dp[i-1],这样就得到了公式。在此之上再考虑0的问题即可。
动态规划公式:dp[n] = Math.max(composite <= 26 ? dp[n-2] + dp[n-1] : dp[n-1])

    public int numDecodings(String s) {
        //dp[n] = Math.max(composite <= 26 ? dp[n-2] + dp[n-1] : dp[n-1])
        if (s.length() == 0) return 0;
        if (s.charAt(0) == '0') return 0;
        int[] dp = new int[s.length() + 1];
        dp[0] = 1;
        dp[1] = 1;
        for (int i = 1; i < s.length(); i++) {
            int cur = (s.charAt(i-1) - '0') * 10 + s.charAt(i) - '0';
            if (s.charAt(i) == '0') {
                if (s.charAt(i-1) == '0' || cur > 26) return 0;
                dp[i+1] = dp[i-1];
                continue;
            }
            if (s.charAt(i-1) == '0') {
                dp[i+1] = dp[i];
                continue;
            }
            dp[i+1]  = cur > 26 ? dp[i] : dp[i] + dp[i-1];
        }
        return dp[s.length()];
    }

在正确的基础上进行优化,由于n只和n-1和n-2有关,因此在更新的过程中,实际只有两个值在发挥作用,因此我们可以省去数组而只用两个值进行更新。代码如下:

    public int numDecodings(String s) {
        //dp[n] = Math.max(composite <= 26 ? 2 * dp[n-2] : dp[n-2], dp[n-1])
        if (s.length() == 0) return 0;
        if (s.charAt(0) == '0') return 0;
        int i_2 = 1;
        int i_1 = 1;
        for (int i = 1; i < s.length(); i++) {
            int cur = (s.charAt(i-1) - '0') * 10 + s.charAt(i) - '0';
            int i_0 = 0;
            if (s.charAt(i) == '0') {
                if (s.charAt(i-1) == '0' || cur > 26) return 0;
                i_0 = i_2;
            } else if (s.charAt(i-1) == '0') {
                i_0 = i_1;
            } else {
                i_0 = cur > 26 ? i_1 : i_1 + i_2;
            }
            i_2 = i_1;
            i_1 = i_0;
        }
        return i_1;
    }

猜你喜欢

转载自blog.csdn.net/katrina95/article/details/85381049