动态规划(基础概念)-斐波那契引出

基本概念(跳转)
首先我们先用一个简单的题目来引入:斐波那契数列
在这里插入图片描述
不过这个题也算它直接给出公式了,所以一般来说可以直接写出最简的写法吧,但不过也是因此大家都会做所以才用这个当例子吧。
在这里说一下这个题的是如何穿上马甲变成另外一个题目的吧
在这里插入图片描述
这两个题本质是一样的;我记得我大二的时候上算法课被这道题弄懵了,现在看来就是斐波那契呗,不过这里没有很明显的告诉我们他的递推公式而已,要自己稍微总结一下下;

第一种方法(递归)

//当然题目保证n是一个正整数
    private static int solutionOne(int n) {
        if(n <= 2)	//递归结束条件
            return 1;
           //当前处理逻辑和向下层递归
        return solutionOne(n-1)+solutionOne(n-2);
    }

这是一个单纯的递归解法,对于递归的话这里就不做详解了(得先把递归弄弄哦),我们在这里给出该递归函数的状态树吧;
在这里插入图片描述
这里只画到了4,但也可以看出同样的参数执行了很多次!这还只是4如果数值一多就会存在大量重复运算!那应该如何避免同样的数值计算多次呢?

方法二(在递归中添加记事本)

那当然是对值进行保存,然后在计算之前查找记事本如果有值那么就不需要计算直接取就可以了:

    private static Map<Integer,Integer> map = null;
    private static int solutionTwo(int n) {
        if(n <= 2 )
            return 1;
        if(map.containsKey(n))
            return map.get(n);
        int result = solutionTwo(n-1)+solutionTwo(n-2);
        map.put(n,result);
        return result;
    }

在计算前先进行判断是否已经被计算过了,如果也已经计算过了那么就直接进行返回,如果没有进行计算那么计算后保存进集合中,统称为记事本(也是所谓的记忆化搜索)。
思想:发现递归树中有大量重复子问题,那么就对子问题的结果进行保存,然后进行查找,就会避免重复计算。先说明:其实这就是所谓的动态规划中的自顶向下的思想也是相对来说符合人的思维方法的;先稍微解释一下,什么是自顶向下:
   就是状态树的顶端也就是从f(n)开始出发,一步一步向下递归,求解;主要表现形式就是上文的状态树;
那么相对应的如何使用自底向上的思维方式呢?

方法三:(递推)

class Solution {
    public int fib(int N) {
        if(N == 0)
            return 0;
        int pre = 1;
        int aft = 1;
        int temp = 1;
        for(int i = 3 ; i <= N ; i++){
            temp = pre+aft;
            pre = aft;
            aft = temp;
        }
        return temp;
    }
}

何为自底向上:
我们从状态f(1),f(2)开始向上递推!因为这个题目解的规律既是当前状态(当前值)等于前两个值之和,因此我们得出递推公式temp = pre + aft;如何从f(1),f(2)开始一步步向上推进,如果要类比于上文的递归树(实际上现在已经不能称其为树了已经是一个线性结构的了),那么就是从最低端向我们的结果进行推进!
由此该题讲解就完毕了,然后我们以该题为例去理解动态规划的一些概念吧

### 基本概念
  • 最优子结构
  • 无后效性
  • 重复子问题
什么样的问题适合动态规划来解决?
一般是用来解决最优问题,但其实主要还是观察题目是否具有其动态规划问题的基本性质;
最优子结构:

问题的最优解包含子问题的最优解:来我们用斐波那契题目进行分析!
(不过要注意的是,对于斐波那契这个较为简单的题目来说并没有最优解之说,因为他的每一个阶段,也就是对应的f(n)只有一个状态,不要取寻找该位置最优的状态!)
虽然没有最优,但不过我们也可以对应出,就是问题的解包含子问题的解。

如何来理解这句话:就是说你要求f(6)是不是他的解来源于f(5)和f(4)只要你把f(5),f(4)的解求出来了就可以求出f(6)的解了

来我们将改结论进行泛化:就是我们需要求f(n)的解,需要求出f(n-1)的解,就可以推出f(n)的解了。

对于稍微复杂一点的题目就有可能在每个阶段有多个状态,这是就需要进行比较获得最优的那个状态。

无后效性

两层含义
1:在推导后面阶段的状态的时候,我们只关心前面的阶段的状态值,不关心这个状态是怎么一步一步推导出来的
2:某个阶段一旦确定,就不受之后阶段决策的影响。
可以取斐波那契这个题目中思考一下,当f(5),f(6)阶段的状态一旦确定,对后面状态的影响就会确定了。在通俗一点就是说f(7) = f(5)+f(6);那么一旦f(5)和f(6)的值确定了,那么就不会受之后的值的影响了

重复子问题

这个概念还是比较好理解的,大家瞧瞧那个递归树的图就可以看出,含有大量的重复子问题。如果看不出来的话,那么考虑读者可以自己多画几层,应该就可以看出来了哈;

存储中间状态pre和aft

就是使用临时变量或者是数组进行中间变量的存储

递推公式(美名其曰:状态转移方程)

这个是动态规划题目的关键,有了状态转移方程就差不多写出来了吧,斐波那契的状态转移:
f(n) = f(n-1) + f(n-2)

总结:

由一个题目进行代入,去理解动态规划的概念,之后应该会写这个题的题解吧;其实第一种解法思想来说,可以说是递归也可以说是回溯,就是穷举所有的状态。然后第二种解法就是在第一种解法的基础上加入缓存,也是经常使用的算法思想空间换时间;然后其实第三种解法和第二种解法的时间复杂度是差不多,只不过第三种进一步缩减了空间复杂度。
然后对于一些难一点的题目呢?如何变难,大概说一下,当然在其他文章也会有体现的;

  • 每个阶段的有多个状态,需要寻找最优的状态,取舍最优子结构
  • 从一维的变成二维或者三维
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值