动态规划算法介绍

动态规划算法介绍:就是解决获取最优解值的算法

- 1.动态规划(Dynamic Programming)算法的核心思想是:将大问题划分为小问题进行解决,从而一步步获取最优解的处理算法
- 2.动态规划算法与分治算法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
- 3.与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。
		(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)
- 4.动态规划可以通过填表的方式来逐步推进,得到最优解.
### 动态规划与分治算法的区别:
### 大家知道动规是由前一个状态推导出来的,而贪心是局部直接选最优的,对于刷题来说就够用了
	分治算法的每个子问题求解都是互相独立的;
	动态规划算法则是:下一个子阶段求解是建立在上一个子阶段求解的基础上;
# 也就是说 ①把问题转换成子问题;  ②并缓存中间结果;
1.递归求解,暴力解,容易超时;

打家劫舍问题,就是0-1背包问题 要么选要么不选;我们用递归解决:

递归三部曲:

- 选择递归函数的参数:一般就是选择随着递归状态而改变的的变量;
- 递归出口
- 递归方向

2.采用动态规划优化递归
动态规划的一般思路:
  1. basecase 就是递归出口;
  2. 状态转移方程就是 递推公式
  3. 缓存中间结果;题目用数组我们就用数组,一维数组用一维数组缓存;二维数组用二维数组缓存;
  4. 顺序,我们必须是知道前一个结果才能知道后一个;

对于动态规划问题,我将拆解为如下五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了!

  1. 1. 确定dp数组(也可能是二维) 以及下标的含义
    2. 确定递推公式 最优子结构
    3. dp数组如何初始化 dp[0] dp[1]等
    4. 确定遍历顺序    从前往后还是从后往前
    5. 举例推导dp数组  看看是否和题目描述的一致
    
e g: 1 .斐波那契数列 我们不用递归 用动态规划来做

题目描述:斐波那契数,通常用 F(n) 表示,形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) = 0,F(1) = 1 F(n) = F(n - 1) + F(n - 2),其中 n > 1 给你n ,请计算 F(n) 。

动规五部曲:
这里我们要用一个一维dp数组来保存递归的结果
1. 确定dp数组以及下标的含义
		dp[i]的定义为:第i个数的斐波那契数值是dp[i]
2. 确定递推公式
为什么这是一道非常简单的入门题目呢?
因为题目已经把递推公式直接给我们了:
	状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];
3. dp数组如何初始化
		题目中把如何初始化也直接给我们了,如下:
		dp[0] = 0;
		dp[1] = 1;
4. 确定遍历顺序
		从递归公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的
5. 举例推导dp数组
		按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2],我们来推导一下,当N为10的时候,dp数组应该是如下的数列:
		0 1 1 2 3 5 8 13 21 34 55
	如果代码写出来,发现结果不对,就把dp数组打印出来看看和我们推导的数列是不是一致的。
public static int fib(int n) {
   
    	//特殊情况
        if (n<=1){
   
            return n;
        }
        int[] dp=new int[n+1];
        //初始化dp数组
        dp[0]=0;
        dp[1]=1;
        for (int i = 2; i <dp.length ; i++) {
   
            dp[i]=dp[i-1]+dp[i-2];//递推公式
        }
        return dp[n];
    }
e g: 2 .爬楼梯
1. 确定dp数组以及下标的含义
		dp[i]: 爬到第i层楼梯,有dp[i]种方法
2. 确定递推公式
	如果可以推出dp[i]呢?从dp[i]的定义可以看出,dp[i] 可以有两个方向推出来。
		首先是dp[i - 1],上i-1层楼梯,有dp[i - 1]种方法,那么再一步跳一个台阶不就是dp[i]了么。
		还有就是dp[i - 2],上i-2层楼梯,有dp[i - 2]种方法,那么再一步跳两个台阶不就是dp[i]了么。
	那么dp[i]就是 dp[i - 1]与dp[i - 2]之和!
		所以dp[i] = dp[i - 1] + dp[i - 2] 。
## 注:在推导dp[i]的时候,一定要时刻想着dp[i]的定义,否则容易跑偏。
		这体现出确定dp数组以及下标的含义的重要性!
3. dp数组如何初始化
	在回顾一下dp[i]的定义:爬到第i层楼梯,有dp[i]中方法。那么i为0,dp[i]应该是多少呢,题目中说了n是一个正整数,题目根本就没说n有为0的情况。所以本题其实就不应该讨论dp[0]的初始化!
		我相信dp[1] = 1,dp[2] = 2,这个初始化大家应该都没有争议的。
		所以我的原则是:不考虑dp[0]如果初始化,只初始化dp[1] = 1,dp[2] = 2,然后从i = 3开始递推,这样才符合dp[i]的定义。

4. 确定遍历顺序
	从递推公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,遍历顺序一定是从前向后遍历的

5. 举例推导dp数组 举例当n为5的时候,dp table(dp数组)应该是这样的
            1 2 3 5 8
            1 2 3 4 5
            数组下标是1开始的
 public static int climbStairs(int n) {
   
        if (n<=2){
   
            return n;
        }
        int[] dp = new int[n+1];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) {
   
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
e g: 3.整数拆分
- 两种情况:
		dp[i]代表要拆的整数i能得到的最大成绩
	1.整数 i 拆成 j 和 i-j , i-j 不再拆分,直接求乘积;乘积为 j* (i-j)
	2.整数 i 拆成 j 和 i-j , i-j 继续作为一个新的整数进行拆分,j* dp[i-j]

递推公式(状态转移方程)就是:

-  dp[i] = max{dp[i], max((i - j) * j, dp[i - j] * j)};
		那么在取最大值的时候,为什么还要比较dp[i]呢?
		因为在递推公式推导的过程中,每次都会计算得出dp[i],我们最后要取最大。
public static int integerBreak(int n) {
   
        //dp[i] 为正整数 i 拆分后的结果的最大乘积
        int[]dp=new int[n+1];
        dp[2]=1;
        //i是从2开始拆的
        for(int i=2;i<=n;i++){
   
            //j的范围是1到i-j
            for(int j=1;j<=i-j;j++){
   
                dp[i]=Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
            }
        }
        return dp[n];
    }

相关推荐

  1. 动态规划算法介绍

    2023-12-11 19:10:06       83 阅读
  2. 动态规划方法介绍

    2023-12-11 19:10:06       41 阅读
  3. 算法动态规划

    2023-12-11 19:10:06       57 阅读
  4. 算法动态规划引入

    2023-12-11 19:10:06       59 阅读
  5. 算法——C/动态规划

    2023-12-11 19:10:06       52 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-11 19:10:06       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-11 19:10:06       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-11 19:10:06       82 阅读
  4. Python语言-面向对象

    2023-12-11 19:10:06       91 阅读

热门阅读

  1. Oracle中decode函数使用

    2023-12-11 19:10:06       56 阅读
  2. MySQL面试

    2023-12-11 19:10:06       59 阅读
  3. 【redis笔记】分布式锁

    2023-12-11 19:10:06       60 阅读
  4. 理解Go语言中的defer

    2023-12-11 19:10:06       62 阅读
  5. 初次参加软考就想报高级,哪个相对容易考?

    2023-12-11 19:10:06       72 阅读
  6. C++可以函数重载而C不可以的原因

    2023-12-11 19:10:06       56 阅读
  7. Springboot 集成 RocketMq5+ (gRPC 协议)

    2023-12-11 19:10:06       80 阅读
  8. 8-Hive原理与技术

    2023-12-11 19:10:06       55 阅读
  9. 【影像组学入门百问】1#---#3

    2023-12-11 19:10:06       70 阅读