有了四步解题法模板,再也不害怕动态规划! | 算法必看系列十六

简介: 动态规划的四步解题法其实是相互递进的,状态的定义离不开问题的拆解,递推方程的推导离不开状态的定义,最后的实现代码的核心其实就是递推方程,这中间如果有一个步骤卡壳了则会导致问题无法解决,当问题的复杂程度增加的时候,这里面的思维复杂程度会上升。用一句话解释动态规划就是 “记住你之前做过的事”,如果更准确些,其实是 “记住你之前得到的答案”。

原文链接

导言

动态规划问题一直是算法面试当中的重点和难点,并且动态规划这种通过空间换取时间的算法思想在实际的工作中也会被频繁用到,这篇文章的目的主要是解释清楚 什么是动态规划,还有就是面对一道动态规划问题,一般的 思考步骤 以及其中的注意事项等等,最后通过几道题目将理论和实践结合。

什么是动态规划

如果你还没有听说过动态规划,或者仅仅只有耳闻,或许你可以看看 Quora 上面的这个 回答。
image.png

How to explain dynamic

用一句话解释动态规划就是 “记住你之前做过的事”,如果更准确些,其实是 “记住你之前得到的答案”。

我举个大家工作中经常遇到的例子。

在软件开发中,大家经常会遇到一些系统配置的问题,配置不对,系统就会报错,这个时候一般都会去 Google 或者是查阅相关的文档,花了一定的时间将配置修改好。

过了一段时间,去到另一个系统,遇到类似的问题,这个时候已经记不清之前修改过的配置文件长什么样,这个时候有两种方案,一种方案还是去 Google 或者查阅文档,另一种方案是借鉴之前修改过的配置,第一种做法其实是万金油,因为你遇到的任何问题其实都可以去 Google,去查阅相关文件找答案,但是这会花费一定的时间,相比之下,第二种方案肯定会更加地节约时间,但是这个方案是有条件的,条件如下:

  • 之前的问题和当前的问题有着关联性,换句话说,之前问题得到的答案可以帮助解决当前问题
  • 需要记录之前问题的答案

当然在这个例子中,可以看到的是,上面这两个条件均满足,大可去到之前配置过的文件中,将配置拷贝过来,然后做些细微的调整即可解决当前问题,节约了大量的时间。

不知道你是否从这些描述中发现,对于一个动态规划问题,我们只需要从两个方面考虑,那就是 找出问题之间的联系,以及 记录答案,这里的难点其实是找出问题之间的联系,记录答案只是顺带的事情,利用一些简单的数据结构就可以做到。

思考动态规划问题的四个步骤

一般解决动态规划问题,分为四个步骤,分别是:

  • 问题拆解,找到问题之间的具体联系
  • 状态定义
  • 递推方程推导
  • 实现

这里面的重点其实是前两个,如果前两个步骤顺利完成,后面的递推方程推导和代码实现会变得非常简单。

这里还是拿 Quora 上面的例子来讲解,“1+1+1+1+1+1+1+1” 得出答案是 8,那么如何快速计算 “1+ 1+1+1+1+1+1+1+1”,我们首先可以对这个大的问题进行拆解,这里我说的大问题是 9 个 1 相加,这个问题可以拆解成 1 + “8 个 1 相加的答案”,8 个 1 相加继续拆,可以拆解成 1 + “7 个 1 相加的答案”,… 1 + “0 个 1 相加的答案”,到这里,第一个步骤 已经完成。

状态定义 其实是需要思考在解决一个问题的时候我们做了什么事情,然后得出了什么样的答案,对于这个问题,当前问题的答案就是当前的状态,基于上面的问题拆解,你可以发现两个相邻的问题的联系其实是 后一个问题的答案 = 前一个问题的答案 + 1,这里,状态的每次变化就是 +1。

定义好了状态,递推方程就变得非常简单,就是 dp[i] = dp[i - 1] + 1,这里的 dp[i] 记录的是当前问题的答案,也就是当前的状态,dp[i - 1] 记录的是之前相邻的问题的答案,也就是之前的状态,它们之间通过 +1 来实现状态的变更。

最后一步就是实现了,有了状态表示和递推方程,实现这一步上需要重点考虑的其实是初始化,就是用什么样的数据结构,根据问题的要求需要做那些初始值的设定。

public int dpExample(int n) {
// 多开一位用来存放 0 个 1 相加的结果
    int[] dp = new int[n + 1];  

    dp[0] = 0;      // 0 个 1 相加等于 0

    for (int i = 1; i <= n; ++i) {
        dp[i] = dp[i - 1] + 1;
    }

    return dp[n];
}

你可以看到,动态规划这四个步骤其实是相互递进的,状态的定义离不开问题的拆解,递推方程的推导离不开状态的定义,最后的实现代码的核心其实就是递推方程,这中间如果有一个步骤卡壳了则会导致问题无法解决,当问题的复杂程度增加的时候,这里面的思维复杂程度会上升。

来源 | 五分钟学算法
作者 | P.yh

相关文章
|
3月前
|
机器学习/深度学习 存储 算法
动态规划算法深度解析:0-1背包问题
0-1背包问题是经典的组合优化问题,目标是在给定物品重量和价值及背包容量限制下,选取物品使得总价值最大化且每个物品仅能被选一次。该问题通常采用动态规划方法解决,通过构建二维状态表dp[i][j]记录前i个物品在容量j时的最大价值,利用状态转移方程避免重复计算子问题,从而高效求解最优解。
523 1
|
10月前
|
存储 算法 Java
算法系列之动态规划
动态规划(Dynamic Programming,简称DP)是一种用于解决复杂问题的算法设计技术。它通过将问题分解为更小的子问题,并存储这些子问题的解来避免重复计算,从而提高算法的效率。
410 4
算法系列之动态规划
|
9月前
|
算法 安全 搜索推荐
套用算法模板备案审核问题增多的原因及解决建议
随着算法备案要求的完善,企业常因使用网上廉价模板而遭遇审核通过率低、问题增多的困境。本文分析了审核不通过的原因,包括模板缺乏针对性、审核标准严格、审核人员主观差异及企业准备不足等,并提出建议:深入了解备案要求、准备详尽材料、避免通用模板、寻求专业帮助。备案后还需持续合规管理,确保算法服务安全运行。
|
11月前
|
算法 Java C++
【潜意识Java】蓝桥杯算法有关的动态规划求解背包问题
本文介绍了经典的0/1背包问题及其动态规划解法。
391 5
|
10月前
|
算法 安全 调度
【动态规划篇】穿越算法迷雾:约瑟夫环问题的奇幻密码
【动态规划篇】穿越算法迷雾:约瑟夫环问题的奇幻密码
|
10月前
|
机器学习/深度学习 算法 测试技术
【动态规划篇】01 背包的逆袭:如何用算法装满你的 “财富背包”
【动态规划篇】01 背包的逆袭:如何用算法装满你的 “财富背包”
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
626 2
动态规划算法学习三:0-1背包问题
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
269 2
|
算法
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
这篇文章介绍了动态规划算法中解决最大上升子序列问题(LIS)的方法,包括问题的描述、动态规划的步骤、状态表示、递推方程、计算最优值以及优化方法,如非动态规划的二分法。
282 0
动态规划算法学习四:最大上升子序列问题(LIS:Longest Increasing Subsequence)
|
算法 Java 程序员
【算法每日一练及解题思路】有n级台阶,一次只能上1级或2级,共有多少种走法?
本文深入解析了“爬楼梯问题”,探讨了递归与迭代两种解法,并提供了Java代码实现。通过分析问题本质,帮助读者理解动态规划技巧,提高解决实际编程问题的能力。关键词:Java, 算法, 动态规划, 爬楼梯问题, 递归, 迭代。
618 0