【算法模板】动态规划(基础DP篇)

【算法模板】动态规划(基础DP篇)

📒博客首页:铁甲小宝同学 📒

🌞文章目的:动态规划基础篇分享🌞

🙏博主也在学习阶段,如若发现问题,请告知,非常感谢🙏

💗同时也非常感谢各位小伙伴们的支持💗

🌈每日一语:你相信光吗? 🌈

将过去和羁绊全部丢弃,不好吝惜那为梦想留下的泪水 。 ——路飞

在这里插入图片描述

前言

博主因最近刷的大部分都是动态规划的算法题,所以也把博主所刷的心得和习题在本篇文章中总结分享给大家,并且希望能帮助到大家。

感谢: 感谢csdn、力扣、代码随想录等平台和大佬们提供的习题和题解!!


什么是动态规划?

动态规划 (英语:Dynamic programming,简称 DP),是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题和最优子结构性质的问题。(百度百科得到的答案)

简单的就是说:用简单的方法来解决复杂的问题!

核心思想:

动态规划的核心就是 有记忆,减少不必要的计算!

熊猫人 max,胖版熊猫人 - 熊猫头斗图表情包 _熊猫人_斗图表情

动态规划的做题方法

一般我们在做动态规划这种题的时候一般会有一下这几个步骤:

  • 定义一个的dp数组。
  • dp数组的初始化。
  • 列举动态规划推导公式。
  • 进行循环遍历逐步改变dp数组的值,直道循环结束能获取我们所需要的值即可。

我们只要上述的几个步骤没有出现什么问题的话,那么这个这个题也就是手到擒拿了!

而上述步骤中比较难的就是 动态规划推导公式 的推导,一般在做题时我们很容易的知道这个题是用动态规划来解决这个问题。但是每次就会卡到动态规划推导公式这个地方(不要问我为什么5555)。所以这个也是我们需要提高的地方!!!

给大家一些 建议 ,在做动态规划题的时候 一定要自己推导自己的动态规划推导公式 ,就算写不出来我们在看题解的时候也可以那我们自己推导出来的公式和官方的公式进行一个对比,每次在做题的时候只要能保证这点,则以后的进步就会越来越大!!!


一维DP

简介

在上面我们已经知道了什么是 DP 了,那么什么又是 一维DP 呢?

一维DP:

通常的讲 一维DP 就是通过一维的数组来满足 推导公式 的一个求解。

int[] dp = new int[10];//则表示创建了一个长度为10的一维DP数组。

//例如:推导公式
dp[i] = max(dp[i - 2] + dp[i - 1] , dp[i])//这个就是一个比较简单的一维DP推导公式!

走进一维DP

上述中我们知道了什么是 一维DP ,那我们就要来走进这个它,并且征服它!同学们来看下面的例题吧。

熊猫何苦为难熊猫(熊猫头)_熊猫_何苦_为难表情

例题:

509. 斐波那契数

题目:

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 01 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1

示例:

输入:n = 2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1

做题步骤:

还记得我们第一步需要怎么来分析的吗?

第一步我们需要确定这题的 DP 数组该怎么去创建?

第二步需要我们推导出本题的 DP 公式。

第三步进行循环得到我们需要的结果。

思路:

通过做题步骤我们能知道这个 DP数组 的长度是 n + 1 (因为需要从0开始到n,所以长度也就是 n + 1

题目所说从 1 后面开始每一项的数字都是前两项的和。通过解析这句话我们能知道我们的 循环是从2开始,到n结束 。而推导公式则就是:

dp[i] = dp[i - 1] + dp[i - 2]

当我们完成上述的步骤时接下来就是将这题给实现了。

代码:

Python版本:

class Solution:
    def fib(self, n: int) -> int:
        if n < 2:
            return n
        dp = [0]* (n + 1)
        dp[1] = 1
        for i in range(2 , n + 1):
            dp[i] = dp[i - 1] + dp[i - 2]
        return dp[n]

Java版本:

class Solution {
    public int fib(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;
        int[] dp = new int[n + 1];
        dp[1] = 1;
        for (int i = 2; i < n + 1; i++){
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

我们做了一个比较简单的DP题,那我们再来看另外一个简单的DP问题吧

题目:

746. 使用最小花费爬楼梯

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

示例:

输入:cost = [10,15,20]
输出:15
解释:你将从下标为 1 的台阶开始。
- 支付 15 ,向上爬两个台阶,到达楼梯顶部。
总花费为 15 

做题步骤:

DP数组 的创建。

推导出本题的 DP 公式。

进行循环。

思路:

在题目的含义中我们已经知道了 用最小的花费来达到顶楼! 则我们需要创建的 DP数组 长度就为 n + 1 (第n 个下标代表的是楼顶)。则也能得到动态规划的公式和循环的开始点和结束点!

动态规划公式:

dp[i] = min(dp[i-1]+cost[i-1],cost[i-2]+dp[i-2])//4开始的循环公式
dp[i] = min(dp[i - 1] + cost[i - 1], cost[i - 2] )//当i是等于3的时候判断方程式
dp[i] = min(cost[i - 1], cost[i - 2])//等于2的时候的一个公式

代码:

Python版本

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        dp = [0 for i in range(len(cost)+1)]
        
        for i in range(2,len(cost)+1):
            if i ==3 :
                dp[i] = min(dp[i - 1] + cost[i - 1], cost[i - 2] )
            elif i ==2 :
                dp[i] = min(cost[i - 1], cost[i - 2])
            else:
             dp[i] = min(dp[i-1]+cost[i-1],cost[i-2]+dp[i-2])
        return dp[len(cost)]

Java版本:

class Solution {
    public int minCostClimbingStairs(int[] cost) {
        int[] dp  = new int[cost.length + 1];
        for(int i = 2; i < cost.length + 1; i ++){
            if (i == 2){
                dp[i] = Math.min(cost[i - 1], cost[i - 2]);
            }
            else if (i == 3){
                dp [i] = Math.min(cost[i - 2] , dp[i - 1] + cost[i - 1]);
            }else{
                dp[i] = Math.min(cost[i - 1] + dp[i - 1] , cost[i - 2] + dp[i - 2]);
            }
        }
        return dp[cost.length];

    }
}

OK,例题看完了,接下来就是来看习题了哦!!!

模块练习题

题目
70 爬楼梯
整数拆分
不同的二叉搜索树
198 打家劫舍
213 打家劫舍 II
337 打家劫舍 III

蝴蝶结版熊猫头脸红 - 熊猫头蝴蝶结系列_蝴蝶结_熊猫头表情

二维DP

上述中我们了解了什么是一维DP,接下来就是简单的 二维DP

简介

什么是 二维DP 呢?

我们知道我们使用一个一维数组就是 一维DP ,那么我们在 一维DP 里面再套一个 一维DP数组 则这个就是一个 二维DP 。简单来说 二维DP 就是 一维DP 中再包含一个 一维DP

img

走进二维DP

题目:

62. 不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

来源:力扣(LeetCode)

示例:

在这里插入图片描述

输入:m = 3, n = 7
输出:28

做题步骤:

我们能通过题目知道这是一个二维的空间,机器人能在这个二维空间经行下或右的移动,当然 二维DP 也是一样首先需要确定一个 DP数组 ,然后确定推导公式,最后循环并得到结果。

思路:

当然啦,二维DP 当然要定义二维数组,推导公式是按照自己的需要来的。

本题的二维数组则就是网格的长和宽:

int[][] dp = new intp[m][n];

因为机器人只能向下和向右移动:

一种是从 (i-1, j) 这个位置走一步到达

一种是从(i, j - 1) 这个位置走一步到达

所以我们能得到其走到每个格子的路径(左边界和上边界的起始值都是1)的推导公式:相邻的左格子和上格子相加。

dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 

循环则就需要嵌套循环,并且从(1,1)开始。

代码:

Python版本

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        dp = [[1]*n] + [[1]+[0] * (n-1) for _ in range(m-1)]
        #print(dp)
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = dp[i-1][j] + dp[i][j-1]
        return dp[-1][-1]

Java版本:

class Solution {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        for(int k = 0; k < m; k ++){
            dp[k][0] = 1;
        }
        for(int l = 0; l < n; l ++){
            dp[0][l] = 1;
        }
        for (int i = 1; i < m; i++ ){
            for(int j = 1; j < n; j++){
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
            }
        }
        return dp[m-1][n-1];

    }
}

OK,下面是整理好的一些 二维DP 习题。

模块练习题

题目
63 不同路径 II
64. 最小路径和
72. 编辑距离

在这里插入图片描述

总结

OK,今天的分享就到这里啦,希望本篇文章能够帮助屏幕前的你!大家看完不要忘了来个三联,这将会是博主最大的动力!!!

溜了溜了,吃饭去了888888。

下期见!

  • 29
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 16
    评论
ACM 算法模板集 Contents 一. 常用函数与STL 二. 重要公式与定理 1. Fibonacci Number 2. Lucas Number 3. Catalan Number 4. Stirling Number(Second Kind) 5. Bell Number 6. Stirling's Approximation 7. Sum of Reciprocal Approximation 8. Young Tableau 9. 整数划分 10. 错排公式 11. 三角形内切圆半径公式 12. 三角形外接圆半径公式 13. 圆內接四边形面积公式 14. 基础数论公式 三. 大数模板,字符读入 四. 数论算法 1. Greatest Common Divisor最大公约数 2. Prime素数判断 3. Sieve Prime素数筛法 4. Module Inverse模逆元 5. Extended Euclid扩展欧几里德算法 6. Modular Linear Equation模线性方程(同余方程) 7. Chinese Remainder Theorem中国余数定理(互素于非互素) 8. Euler Function欧拉函数 9. Farey总数 9. Farey序列构造 10. Miller_Rabbin素数测试,Pollard_rho因式分解 五. 图论算法 1. 最小生成树(Kruscal算法) 2. 最小生成树(Prim算法) 3. 单源最短路径(Bellman-ford算法) 4. 单源最短路径(Dijkstra算法) 5. 全源最短路径(Folyd算法) 6. 拓扑排序 7. 网络预流和最大流 8. 网络最小费用最大流 9. 网络最大流(高度标号预流推进) 10. 最大团 11. 二分图最大匹配(匈牙利算法) 12. 带权二分图最优匹配(KM算法) 13. 强连通分量(Kosaraju算法) 14. 强连通分量(Gabow算法) 15. 无向图割边割点和双连通分量 16. 最小树形图O(N^3) 17. 最小树形图O(VE) 六. 几何算法 1. 几何模板 2. 球面上两点最短距离 3. 三点求圆心坐标 4. 三角形几个重要的点 七. 专题讨论 1. 树状数组 2. 字典树 3. 后缀树 4. 线段树 5. 并查集 6. 二叉堆 7. 逆序数(归并排序) 8. 树状DP 9. 欧拉路 10. 八数码 11. 高斯消元法 12. 字符串匹配(KMP算法) 13. 全排列,全组合 14. 二维线段树 15. 稳定婚姻匹配 16. 后缀数组 17. 左偏树 18. 标准RMQ-ST 19. 度限制最小生成树 20. 最优比率生成树(0/1分数规划) 21. 最小花费置换 22. 区间K大数 23. LCA - RMQ-ST 24. LCA – Tarjan 25. 指数型母函数 26. 指数型母函数(大数据) 27. 单词前缀树(字典树+KMP) 28. FFT(大数乘法) 29. 二分图网络最大流最小割 30. 混合图欧拉回路 31. 无源汇上下界网络流 32. 二分图最小点权覆盖 33. 带约束的轨道计数(Burnside引理) 34. 三分法求函数波峰 35. 单词计数,矩阵乘法 36. 字符串和数值hash 37. 滚动队列,前向星表示法 38. 最小点基,最小权点基

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铁甲小宝同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值