算法重新出发:2.动态规划算法

本文详细解读LeetCode 91题解码方法的动态规划解决方案,通过实际案例阐述如何利用状态转移方程处理多阶段决策问题,优化0和非0数字组合策略。理解动态规划在决策问题中的应用和步骤,包括创建dp数组,状态转移规则,及最终返回解码方案总数。
摘要由CSDN通过智能技术生成

算法重新出发:2.动态规划

  • leetcode 91. 解码方法
    在这里插入图片描述
class Solution {
public:
    int numDecodings(string s) {
        if(s[0]=='0') return 0;
        int dp[s.size()+1];
        dp[0]=1;
        dp[1]=1;
        for (int i = 1; i < s.size(); 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]>='1' && s[i]<='6')) {
                    dp[i+1] = dp[i]+dp[i-1];
                }
                else dp[i+1] = dp[i];
            }
        }
        return dp[s.size()];
    }
};

动态规划能解决的问题是多阶段决策问题
如果一类活动过程可以分为若干个互相联系的阶段,在每一个阶段都需作出决策,一个阶段的决策确定以后,会影响到下一个阶段的决策,从而确定活动路线,则称它为多阶段决策问题。各个阶段的决策构成一个决策序列,称为一个策略。每一个阶段都有若干个决策可供选择,因而就有许多策略供我们选取。

如今天的leetcode 91. 解码方法
在这里插入图片描述11106可以分解为如上两种消息,10定死是由于0只能和前面的1或2组合,6无法再组合

if (s[i] == '0') {
                if (s[i-1] == '1' || s[i-1] == '2') dp[i+1] = dp[i-1];
                else return 0;
            }

当当前数为0时,0前的数若是1或2,则无法和别的数组合,0所对应的方案数和0的前两个数对应的方案数是一样的;0前的数若是0或3-9,则根本不可能组合,直接返回0
在这里插入图片描述

if (s[i-1]=='1' || (s[i-1]=='2' && s[i]>='1' && s[i]<='6'))  dp[i+1] = dp[i]+dp[i-1];
else dp[i+1] = dp[i];

当当前数不为0时,若前一个数为1,则肯定能组合;或者当当前数为0-6时,若前一个数为2也能组合,对应的方案数为前一个数对应方案数个数加前两个数对应的方案数;否则则不能组合,对应的方案数为前一个数对应的方案数,因为自成一个,如11106中的6

上面这些代码就是找出来的状态转移方程,可以看出是解决了一个个小问题最后得到到最后的方案数的。能用动态规划解决的问题是上面说的决策问题被重复调用得出的,像226中的22,只有组合和不组合两种选择,每次都会影响到后续路径,若22组合则6只能单个,22不组合则6可以选择组合或不组合,而若是226后面还有数字,也会被6是否组合影响,但是后续的方案数和前面的组合有关却又可以通过状态转移方程直接调用前面的方案数而不是从头决定是否组合,这就是动态规划所带来的好处。

动态规划步骤:

  1. 创建一个一维数组或者二维数组,保存每一个子问题的结果,具体视题目而定(一维数组可以运用滚动数组的方式来解决,即一位数组中的值不停的变化
  2. 设置数组边界值,如上题中的`dp[0]=1; dp[1]=1;
  3. 找出状态转移方程,即每个状态跟上一个状态的关系,根据方程写出代码
  4. 返回值,一般是数组的最后一个或者二维数组的最右下角

上述代码因为从循环1开始,又有涉及到前两个数的状态转移方程,所以我把dp的下标全都加了1,若是用滚动数组的方式解决,则代码如下:

class Solution {
public:
    int numDecodings(string s) {
        if(s[0]=='0') return 0;
        int a1 = 1;
        int a2 = 1;
        for (int i = 1; i < s.size(); i++) {
            if (s[i] == '0') {
                if (s[i-1] == '1' || s[i-1] == '2') a2 = a1;
                else return 0;
            }
            else {
                if (s[i-1]=='1' || (s[i-1]=='2' && s[i]>='1' && s[i]<='6')) {
                    a2 = a2+a1;
                }
            }
            a1 = tem;
        }
        return a2;
    }
};
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值