dp动态规划

一、认识动态规划

前言:近期我在慢慢刷动态规划的题,虽然还是入门阶段,但还是准备记录我动态规划前期是如何刷题过程

先根据一个例题来引入动态规划——换零钱

  1. 提出问题:要求使用1,5,11的钞票面额进行换总金额为w的最小张数
  2. 分析问题:在兑换的最终情况下(即换一最后一张面额的情况),要么是面额为1,要么5,要么11,所以

我们可以得出:(f(w)表示换w金额需要的最少张数)

  • f(w) = f(w - 1) + 1; //该式子表示的是如果要得出f(w),就用前面已得出的f(w - 1) 加上一张面额为1的钞票即可
  • f(w) = f(w - 5) + 1;//该式子表示的是如果要得出f(w),就用前面已得出的f(w - 5) 加上一张面额为5的钞票即可
  • f(w) = f(w - 11) + 1;

故我们可知,若是求最少换零钱的张数就是

​ f(w - 1) & f(w - 5) & f(w - 11)

​ 三个中最小的那一个

​ 3. 给出具体例子

那么,假如w=15的时候,同样,钞票面额分别为1,5,11,我们该取那种钞票呢?当然是各种方案中,cost值最低的那一个!- 取1:cost = f(14) + 1 = 4 + 1 = 5;- 取5:cost = f(10) + 1 = 2 + 1 = 3;- 取11:cost = f(4) + 1 = 4 + 1 = 5;再次深度解释一下:其中第二个取5的式子:f(10) = f(10 - 5) + 1 = 1 + 1; 即子问题的解;第三个取11的式子:f(4) = f(4 - 1) + 1 = 4;
  1. 得出结论

    大致我们可以得出,我们所求的就是前面 当前最优值 = 前面最优值 + 1

    我们将求解f(w)就可以理解为求解多个子问题来达到求解f(w)

    这就是dp --> 动态规划

  2. 解决问题的特点
    1. 能将问题拆成几个问题,且满足无后效性(即不管前面的过程,只需要得出前面的子最优解解即可)

    2. 最优子结构性质,能够由子问题推导出结果

    3. 详细来说:

      • 求最大最小值

        • 从左上角走到右下角路径的最大数字和
        • 最长上升子序列
        • 最长等差序列
        • 最少换钱张数
      • 计数
        • 有多少种方式走到右下角
        • 有多少种方法选出k个数使得和是sum
        • 爬楼梯
      • 判断
        • 是否存在先手赢,取石子游戏
  3. 解题一般步骤
    1. 判断是否是最优问题,并存在子问题
    2. 确定dp数组用一维或者更多,并且表示什么意思
    3. 比如dp[i][j】,表示为从i下标到j下标长度的回文子串个数
    4. 推导出dp状态方程,和判断条件
    5. 确定好dp初始数组长度,和是否设立初始值
    6. 选用合适的循环条件达到自己的目的

二、下面进行具体刷动规的题型

  • 斐波那契数

  • 零钱兑换

  • 最长递增子序列

  • 爬楼梯

  1. 斐波那契数

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

    F(0) = 0,F(1) = 1
    F(n) = F(n - 1) + F(n - 2),其中 n > 1
    给定 n ,请计算 F(n) 。

    示例 1:

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

    输入:n = 3
    输出:2
    解释:F(3) = F(2) + F(1) = 1 + 1 = 2
    示例 3:

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

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/fibonacci-number
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    class Solution {public int fib(int n) {//动态规划 dp[i] 表示的是第i个数表示的值if (n == 0) return 0;  //处理特殊情况int []dp = new int[n + 1];    //数组长度初始化,一般情况下多一点dp[0] = 0;    //初始化dp[1] = 1;for (int i = 2; i <= n; i++){    //循环过程dp[i] = dp[i - 1] + dp[i - 2];  //状态方程}return dp[n];    //得到最终结果}
    }
    
  2. 零钱兑换

    给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

    计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

    你可以认为每种硬币的数量是无限的。

    示例 1:

    输入:coins = [1, 2, 5], amount = 11
    输出:3
    解释:11 = 5 + 5 + 1
    示例 2:

    输入:coins = [2], amount = 3
    输出:-1
    示例 3:

    输入:coins = [1], amount = 0
    输出:0

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/coin-change
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    class Solution {public int coinChange(int[] coins, int amount) {//动态规划int[] dp = new int[amount+1];Arrays.fill(dp, amount+1);//base casedp[0] = 0;// 外层的for循环在遍历时实现遍历所有状态的所有取值for(int i = 0; i < dp.length; i++){// 内层for循环求在所有选择中的最小值for(int coin : coins){//子问题无解,跳过if(i - coin < 0){continue;}//状态转移dp[i] = Math.min(dp[i],1+dp[i-coin]);}}//查看金额能不能算出来return (dp[amount] == amount+1 ? -1 : dp[amount]);//暴力递归——超时// if (amount == 0){//     return 0;// }// if (amount < 0){//     return -1;// }// int min = Integer.MAX_VALUE;// for (int i = 0; i < coins.length; i++){//     int temp = coinChange(coins, amount - coins[i]);//     if (temp == -1){continue;}//     min = Math.min(min, temp + 1);// }// return min == Integer.MAX_VALUE ? -1 : min;}
    }
    
  3. 最长递增子序列

    给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

    子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

    示例 1:

    输入:nums = [10,9,2,5,3,7,101,18]
    输出:4
    解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
    示例 2:

    输入:nums = [0,1,0,3,2,3]
    输出:4
    示例 3:

    输入:nums = [7,7,7,7,7,7,7]
    输出:1

    来源:力扣(LeetCode)
    链接:https://leetcode.cn/problems/longest-increasing-subsequence
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    class Solution {public int lengthOfLIS(int[] nums) {//动态规划if (nums == null || nums.length == 0){return 0;}//求最优解,利用dp,输出为长度,故new一维dp数组,dp[i]初始为1,状态为nums[i]和nums[j]大小比较,更新状态值//dp[i]表示的是长度为i + 1的数组最大递增子序列int len = nums.length;int result = 1;int []dp = new int[len + 1];Arrays.fill(dp, 1); //填充dp数组,全部为1for (int i = 1; i < len; i++){for (int j = 0; j < i; j++){if (nums[j] < nums[i]){   //判断条件dp[i] = Math.max(dp[i], dp[j] + 1); //状态转移}result = Math.max(dp[i], result);   //由于有子问题最大值,故设立变量result更新最大值}}return result; //输出dp[len - 1]为长度为len - 1的数组最大递增子序长度}
    }
    
  4. 爬楼梯
    1. 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

      每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

      示例 1:

      输入:n = 2
      输出:2
      解释:有两种方法可以爬到楼顶。

      1. 1 阶 + 1 阶
      2. 2 阶
        示例 2:

      输入:n = 3
      输出:3
      解释:有三种方法可以爬到楼顶。

      1. 1 阶 + 1 阶 + 1 阶
      2. 1 阶 + 2 阶
      3. 2 阶 + 1 阶

      来源:力扣(LeetCode)
      链接:https://leetcode.cn/problems/climbing-stairs
      著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    class Solution {public int climbStairs(int n) {//dp[i] 表示的是爬到第i阶方法数int []dp = new int[n + 1];dp[0] = 1;  //初始化dp[0]为1——>以至于后面for循环dp[2]能够得出正确答案,只要1和2是正确答案,后面可得正确取值dp[1] = 1; for (int i = 2; i <= n; i++){dp[i] = dp[i - 1] + dp[i - 2]; //分为1步和2步两种情况,并且求种数,为两者之和}return dp[n];}
    }
    

总结:看完这几道例题,大家也许会发现主要还是dp一维数组,并且算是比较简单的,但是对于刚开始入门动规的话,应该能够起到一定的作用,力扣上面也有一个动态规划计划集,我暂时也是根据上面做的。大家有兴趣可以去跟着做一做。如有不足,请与我联系更改。

我把链接放在这里,大家有兴趣可以试试:力扣-动态规划入门

初识动态规划(一)简单入门动态规划与上手操作相关推荐

  1. 通过金矿模型介绍动态规划(经典入门)

    对于动态规划,每个刚接触的人都需要一段时间来理解,特别是第一次接触的时候总是想不通为什么这种方法可行,这篇文章就是为了帮助大家理解动态规划,并通过讲解基本的01背包问题来引导读者如何去思考动态规划.本 ...

  2. 【动态规划】简单背包问题II

    问题 J: [动态规划]简单背包问题II 时间限制: 1 Sec  内存限制: 64 MB 提交: 127  解决: 76 [提交] [状态] [讨论版] [命题人:admin] 题目描述 张琪曼:& ...

  3. 从入门到入土:Python爬虫学习|Selenium自动化模块学习|简单入门|轻松上手|自动操作浏览器进行处理|chrome|PART01

    此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...

  4. 一个简单的动态规划问题---小偷案例

    Java算法训练-小偷案例 文章目录 Java算法训练---小偷案例 前言 一.案例描述 二.问题分析 三.代码示例 总结 前言 动态规划是一种算法技巧,先举一个例子:   如何让一个四岁的小孩理解动 ...

  5. 题解:魔法少女(动态规划超简单)

    前些时间虚渊玄的巨献小圆着实火了一把.在黑长直(小炎)往上爬楼去对抗魔女之夜时,她遇到了一个问题想请你帮忙.因为魔女之夜是悬浮在半空的,所以她必须要爬楼,而那座废墟一共有 nn 层,而且每层高度不同, ...

  6. 动态规划走楼梯_动态规划问题为什么要画表格?

    ❝ 本文是我的 91 算法第一期的部分讲义内容.91 算法第一期已经接近尾声,二期的具体时间关注我的公众号即可,一旦开放,会第一时间在公众号<力扣加加>通知大家. ❞ 动态规划可以理解为是 ...

  7. [MVC.NET] Asp.Net MVC3 简单入门第一季

    转自:http://www.cnblogs.com/fly_dragon/archive/2011/10/12/2208042.html 初识Asp.Net MVC2.0 初识Asp.Net MVC2 ...

  8. Matlab 界面设计简单入门(App Designer)

    新版Matlab交互界面基本操作 注意:本教程仅适用于2016b以后版本,建议安装2019b以后最新版本Matlab 与原来的GUIDE不同,新版的App Designer程序编写更加合理,更加好看, ...

  9. 【CMS建站】写给大家看的网站制作教程03—零基础学网站制作的简单入门指南...

    作者 | 杨小爱 来源 | web前端开发(ID:web_qdkf) 在上一篇<[CMS建站]写给大家看的网站制作教程02-网站制作的工具介绍与下载安装>文章中,我详细的讲解了关于制作一个 ...

最新文章

  1. js解决异步的方法汇总
  2. 如何为程序分配合适的栈空间?
  3. opengl win32 nehe
  4. 计算机专业哪些证书可以抵个税,2020年度个人所得税汇算清缴进行时 职业资格证书有哪些能抵扣个税?...
  5. 一个介绍傅立叶变换的好文章
  6. map怎么转化dto_阿里面试:为什么Map桶中个数超过8才转为红黑树
  7. golang语言的类型
  8. 全卷机神经网络图像分割(U-net)-keras实现
  9. 18-黑马程序员------OC语言学习笔记---封装
  10. 计算机网络实验报告 接墙上的,计算机网络实验报告模板.doc
  11. C/C++结构体语法总结
  12. 基于改进麻雀算法优化变分模态分解(IAMSSA—VMD)的信号分解方法
  13. 代码检测vc2013环境是否已经安装了
  14. Java学习笔记:根据Excel工资表生成工资条
  15. 最小生成树详解(模板 + 例题)
  16. 浅谈利用强化学习A3C玩转超级玛丽奥
  17. 及时复盘的好处_及时复盘,促进成长
  18. Python+bs4实现爬取小说并下载到本地
  19. Pod2g已发现可完美越狱iOS 5的漏洞
  20. 成都中医药大学计算机基础试题,成都中医药大学2016年春季学期期末考试计算机基础-成教()解剖.doc...

热门文章

  1. python 知识点视频,Python超详细入门教程-Python基础视频教程-千锋教育视频资源库...
  2. 判断一个字符数据是否是数字字符
  3. 《未来简史(下)》万维钢解读
  4. 解决光纤猫恢复出厂功能后的上网问题
  5. ARTS-第-22-期
  6. 解决Visio中对象不能通过键盘方向键微调位置
  7. 基于Vue实现的多条件筛选功能(类似京东和淘宝功能)
  8. 使用pandas的话,如何直接删除这个表格里面X值是负数的行?
  9. 自然资源一体化平台(一站式服务平台)
  10. SparkLink星闪技术之SLB概述