首页 > 代码库 > [C++]LeetCode: 55 Decode Ways

[C++]LeetCode: 55 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.

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.

思路:

设置动态数组dp[i], dp[i]表示字符串 s[0,1,2,....,i-1]的decode way的个数。

注意,如果序列中有不能匹配的0,那么解码的方法是0,比如序列012,,100(第二个0可以和1组成10,但是第三个0不能匹配)。

分成两种情况讨论,考虑末尾一个数字以及考虑末尾两个数字。动态规划方程:

初始条件:dp[0] = 1(根据判断两个数字dp[2] += dp[0] 确定), dp[1] = (s[0] == ‘0‘) ? 0 :1

递推公式:1.考虑s[0,1,2,...,i-1]末尾一个数字当做一个字母考虑,dp[i]【1】 = s[i-1] == 0 ? 0 : dp[i-1] 

  2.考虑s[0,1,2,...,i-1]末尾两个数字当做一个字母考虑,dp[i]【2】 = isValid(s[i-2, i-1]) == true ? dp[i-2] :0

  3. dp[i]  = dp[i]【1】+ dp[i]【2】

Attention:

1. 初始条件dp[0]的设置,需要根据代码具体含义确定,需符合实际意义(dp[2] += dp[0],此处dp[0]表示s[0,1]代表一个字母,所以取1) 

2. 如果序列中有不能匹配的0,那么解码的方法是0。 这点容易忽视,一定要注意。如果某字符为0,则不能解码,只考虑它是否可以前一个字符组成合法字符。

3. 加入合法字符判断的helper程序(isValid()),可以使代码含义更加清晰。但是也可以采取直接判断。代码如下:

for(int i = 2; i <= len; i++)
        {
            if(s[i-1] != '0')
                dp[i] = dp[i-1];
            else dp[i] = 0;
            if(s[i-2] == '1' || (s[i-2] == '2' && s[i-1] <= '6'))
                dp[i] += dp[i-2];
        }

4. 动态方程的递推方式,以及dp[i]的含义确定,需要准确和考虑全面。

复杂度:O(N)

AC Code:

class Solution {
public:
    int numDecodings(string s) {
        int len = s.length();
        if(len == 0) return 0;
        
        //dp[i]表示s[0,1,...,i-1]的解码方法数目
        int dp[len+1];
        
        //初始化dp[0],dp[1]
        dp[0] = 1;
        if(s[0] != '0')
        {
            dp[1] = 1;
        }
        else
        {
            dp[1] = 0;
        }
        
        for(int i = 2; i <= len; i++)
        {
            //如果末尾数字为无效0,则dp为0
            if(isValid(s.substr(i-1, 1)))
            {
                dp[i] = dp[i-1];
            }
            else
            {
                dp[i] = 0;
            }
            
            if(isValid(s.substr(i-2, 2)))
            {
                dp[i] += dp[i-2];
            }
        }
        
        return dp[len];
    }

public:
    bool isValid(string str)
    {
        //如果str中含无效的0,如“02”,解码失败
        if(str[0] == '0')
            return false;
        int num = std::stoi(str);
        if(num >= 1 && num <= 26)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
};



[C++]LeetCode: 55 Decode Ways