动态规划-01-思维过程

动态规划思路整理:

  1. 首先,动态规划问题的一般形式就是【求最值】。比如求最长递增子序列呀,最小编辑距离等。
  2. 既然是要求最值,核心问题是什么呢?求解动态规划的核心问题是【穷举】。因为要求最值,肯定要把所有可行的答案穷举出来,然后在其中找最值。
  3. 动态规划的穷举有点特别,因为这类问题存在【重叠子问题】,如果暴力穷举的话效率会极其低下,所以需要【备忘录】或者【DP table】来优化穷举过程,避免不必要的计算。
  4. 确定【最优子结构】,列出【状态转移方程】
    在这里插入图片描述

考虑能否将问题规模减小,思考如何由较小规模问题的解获得最终问题的解

总结: 解决动态规划问题最难的地方有两点:

  • 如何定义 f(n)
  • 如何通过 f(1), f(2), … f(n - 1)推导出 f(n),即状态转移方程

1. 递归

有了状态转移方程,实际上已经可以直接用递归进行实现了。

int f(vector<int>& nums, int i)
{
    int a = 1;
    for(int j = 0; j < i; ++j)
    {
        if(nums[j] < nums[i])
        ¦   a = max(a, f(nums, j) + 1);
    }
    return a;
}

2. 自顶向下(记忆化)

递归的解法需要非常多的重复计算,如果有一种办法能避免这些重复计算,可以节省大量计算时间。记忆化就是基于这个思路的算法。在递归地求解子问题 f(1)f(1), f(2)f(2)… 过程中,将结果保存到一个表里,在后续求解子问题中如果遇到求过结果的子问题,直接查表去得到答案而不计算。

int f(vector<int>& nums, int i, vector<int>& dp)
{
    if(dp[i] != -1) return dp[i];
    int a = 1;
    for(int j = 0; j < i; ++j)
    {
        if(nums[j] < nums[i])
        ¦   a = max(a, f(nums, j) + 1);
    }
    dp[i] = a;
    return dp[i];
}

对于这种将问题规模不断减少的做法,我们把它称为自顶向下的方法。

3. 自底向上(迭代)

在自顶向下的算法中,由于递归的存在,程序运行时有额外的栈的消耗。

有了状态转移方程,我们就知道如何从最小的问题规模入手,然后不断地增加问题规模,直到所要求的问题规模为止。在这个过程中,我们同样地可以记忆每个问题规模的解来避免重复的计算。这种方法就是自底向上的方法,由于避免了递归,这是一种更好的办法。

但是迭代法需要有一个明确的迭代方向,例如线性,区间,树形,状态压缩等比较主流的动态规划问题中,迭代方向都有相应的模式。参考后面的例题。但是有一些问题迭代法方向是不确定的,这时可以退而求其次用记忆化来做。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值