LeetCode第 91 题:解码方法(C++)

91. 解码方法 - 力扣(LeetCode)

很坑,亲测输入会出现0,而且从前往后条件真的多到哭,面向if-else编程,我真的想死:

class Solution {
public:
    int dp(string& s, int i, int j){
        int n = j - i + 1;
        if(n == 0)  return 0;
        if(n == 1)  return s[i] == '0' ? 0 : 1;
        if(n == 2){
            if(s[i] == '0') return 0;
            if(s[i] > '2') return s[j] == '0' ? 0 : 1;
            if(s[i] == '2' && s[j] > '6') return 1;
            if(s[j] == '0')    return 1;
            return 2;
        }
        if(s[i] > '2')  return dp(s, i+1, j);
        if(s[i] == '2'){
            if(s[i+1] == '0')   return dp(s, i+2, j);//"20"开头
            else if(s[i+1] < '7')  return dp(s, i+1, j) + dp(s, i+2, j);// > "26"
            else return dp(s, i+1, j);
        }
        if(s[i] == '0') return 0;//首元素为0
        if(s[i+1] == '0') return dp(s, i+2, j);//首元素为1,次元素为0
        return dp(s, i+1, j) + dp(s, i+2, j);
    }
    int numDecodings(string s) {
        return dp(s, 0, s.size()-1);
    }
};

上述代码判断条件繁多,递归栈很深,而且效率极低。。。

正确方法肯定不是这样的。

假设我们现在考虑已经解码了字符串的前i-1个字符,现在轮到了第 i 个字符,进行分情况讨论(dp[i]表示前 i 位的解码方法种数):

1、如果s[i] == '0',那么s[i]不能单独解码,必须和它前面的字符s[i-1]联合:

  • 如果s[i-1] = 1 or 2,那么s[i-1]s[i]只能被联合译码,而且只有这一种情况:dp[i] = dp[i-2]
  • 如果s[i-1] 是 0 或者3~9,那么就无法译码,直接 return 0。

2、当s[i] != '0'时:

  • 如果s[i-1] == '1',此时,s[i]可以和s[i-1]可以联合译码,也可以单独译码,dp[i] = d[i-1] + dp[i-2]
  • 如果s[i-1] == '2' && s[i] <= '6',此时s[i]可以和s[i-1]可以联合译码,也可以单独译码,dp[i] = d[i-1] + dp[i-2]
  • 其他的情况,s[i], s[i-1]只能分开单独译码,dp[i] = dp[i-1]

稍许调整翻译成初步代码:

class Solution {
public:
    int numDecodings(string s) {
        int n = s.size();
        if(n == 0 || s[0] == '0') return 0;//首尾为0无法解码
        
        vector<int> dp(s.size() + 1);
        dp[0] = 1; dp[1] = 1;
        for(int i = 1; i < n; ++i){
            if(s[i] == '0') {
                if(s[i-1] == '1' || s[i-1] == '2')  dp[i+1] = dp[i-1];
                else return 0;
            }else{
                if(s[i-1] == '1' || (s[i-1] == '2' && s[i] <= '6')) dp[i+1] = dp[i] + dp[i-1];
                else dp[i+1] = dp[i];
            }
        }
        return dp.back();
    }
};

最近动态规划题目做了挺多的,但是很多时候拿到新题目还是会没思路,做不到举一反三-_-

如果需要进行优化的话,可以看到状态 i 最多只和前面两个 i-1, i-2有关,所以三个遍变量或者两个变量就能实现状态转移。

class Solution {
public:
    int numDecodings(string s) {
        int n = s.size();
        if(n == 0 || s[0] == '0') return 0;
        
        //vector<int> dp(s.size() + 1);
        //dp[0] = 1; dp[1] = 1;
        int pre = 1, cur = 1;
        int tmp;
        for(int i = 1; i < n; ++i){
            tmp = cur;
            if(s[i] == '0') {
                if(s[i-1] == '1' || s[i-1] == '2')  cur = pre;
                else return 0;
            }else{
                if(s[i-1] == '1' || (s[i-1] == '2' && s[i] <= '6')) cur = cur + pre;
                //else cur = cur;//可以省略
            }
            pre  = tmp;
        }
        return cur;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值