动态规划学习记录

序言:

在学习使用动态规划的过程中一直没有学习到其精髓,直到我在leetcode上刷到一个题目,在寻求解法的时发现了一篇文章(https://zhuanlan.zhihu.com/p/365698607 ),我觉得对我很有帮助,于是就对学到的知识进行了摘录与梳理。

什么是动态规划?

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

​    简单来说,动态规划其实就是,给定一个问题,我们把它拆成一个个子问题,直到子问题可以直接解决。然后呢,把子问题答案保存起来,以减少重复计算。再根据子问题答案反推,得出原问题解的一种方法。

​    动态规划与递归的相同点是把它拆成一个个子问题,但是不同的是它会将子问题的结果保存起来,避免重复计算,以此来提升效率。递归是自顶向下,而动态规划是自底向上。

动态规划的核心思想

拆分子问题,记住过往,减少重复计算。

了解动态规划的简单例子

问题:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

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

问题分析:

  • 要想跳到第10级台阶,要么是先跳到第9级,然后再跳1级台阶上去;要么是先跳到第8级,然后一次迈2级台阶上去。

  • 同理,要想跳到第9级台阶,要么是先跳到第8级,然后再跳1级台阶上去;要么是先跳到第7级,然后一次迈2级台阶上去。

  • 要想跳到第8级台阶,要么是先跳到第7级,然后再跳1级台阶上去;要么是先跳到第6级,然后一次迈2级台阶上去。

通用公式

 

//递归解法
 public int climbStairs(int n) {
        return fun(n);
    }

    public static int fun(int n){

        if(n == 1){
            return 1;
        }else if(n == 2){
            return 2;
        }
        return fun(n-1)+fun(n-2);
    }
//动态规划解法
 public int climbStairs(int n) {
        
        //数组用于存储子问题的结果
        int[] array = new int[n+1];

        //计算子问题,通过子问题的结果得出问题的结果
        for(int i = 1;i <=n;i ++){

            if(i == 1){//为1的特殊情况
                array[i] = 1; 
            }else if(i == 2){//为2的特殊情况
                array[i] = 2;
            }else{//楼顶楼梯数大于2时,可通过子问题的结果计算得出我们想要的结果
                array[i] = array[i-1] + array[i-2];
            }

        }
    
        return array[n];
    }

结果:

递归算法在leetcode上提交超时

而动态规划算法在leetcode上顺利通过

分析:

递归算法由于计算了子问题,通过分析代码可得时间复杂度为O(2^n)

而动态规划算法,只遍历了一次,所以时间复杂度为O(n)

从中可以动态规划的效率是很高的。

总结:

  • 穷举分析:通过穷举找出规律

  • 确定边界:问题不可能一直被拆分,一定有最底层的子问题可以直接得出结果。

  • 找出规律,确定最优子结构:即确保子问题最优,这样我们之后通过子问题计算出的结果才会最优。

  • 写出状态转移方程:即将所找到的规律转换为代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值