动态规划浅谈(一)

为什么要学习动态规划

1、动态规划确实在工作和生活中确实会用到,比如打游戏。
2、非常锻炼思维。
3、有些动态规划的题确实很有意思。

动态规划三板斧。

动态规划虽然听着很高端但是他有套路可寻,遇到问题往三板斧上面套就可以了。
1、定义是什么。
2、归纳推导公式。
3、初始化变量。
这三步,步步依赖,首先要定义问题,才能归纳,通过归纳函数,才能知道我们需要初始化哪些值。甚至我们循环从大到小还是从小到大也和推导公式有关,所以我们解决问题的时候千万要注意顺序。

问题解析

1、这是一个很简单的题,递推公式和初始值已经给你了,既然这两个都有了,那就不用再自己定义了,直接代码实现就ok了。

在这里插入图片描述

2、跳台阶

在这里插入图片描述
首先按照我们的三板斧来应对。
a、定义是什么,这里求的是多少种跳法,定义f(x) 表示跳上x个台阶的时候,有多少种跳法。
b、推导公式,动态规划需要从宏观考虑,不要考虑太多,假设现在你要到第x个台阶上去,那么你只有两种路径上来,一个是从x-2跳两步,一个是从x-1跳一步上来,那么就有f(x)=f(x-1)+f(x-2)
在这里插入图片描述
c、初始值,根据推导公式分析,x需要从2开始,否则会出现负数,则f(0),f(1)需要初始化。
这里f(0)的值可能有疑惑,其实你可以根据f(2)倒推,因为上两层台阶只有两种方式,所以f(0)一定等于1。
代码如下:

public class Solution {
    public int jumpFloor(int target) {
        int[] f = new int[target+1];
        f[0] = 1;
        f[1] = 1;
        for( int i=2; i<target+1; i++ ){
            f[i] = f[i-1]+f[i-2];
        }
        return f[target];
    }
}
3、最小花费怕楼梯

在这里插入图片描述
a、定义是什么,与上题类似,显而易见这里f(x)表示爬到第x个台阶时候的最小花费。并且这里如果不经过x,不需要算上x的花费。所以如果x是最顶端则不需要经过x,所以不算cost[x].
b、那么推导公式呢,
在这里插入图片描述
c、初始值,这里可以看到还是要求出f(0),f(1)的值,后面的值才能推导,代码如下:

  public int minCostClimbingStairs (int[] cost) {
        int[] f = new int[cost.length+1];
        f[0] = cost[0];
        f[1] = cost[1];
        for( int i=2; i<cost.length; i++ ){
            f[i] = Math.min(f[i-1],f[i-2])+cost[i];
        }
        return Math.min(f[cost.length-1],f[cost.length-2]);
    }

d、这里解释下,为啥返回的是cost.length-1和cost.length-2的最小值呢,因为可能从这两个任意一个地方跳到最高点,所以取最小值。那为什么不加cost[cost.length]呢,因为cost[cost.length]是过路费,我只是到达最高点,并不需要经过,所以这里不需要加上cost[cost.length]。

最长公共子序列

在这里插入图片描述
以上都是一维数组,这里就是一个二维数组了。
a、首先定义是什么,这个题如果我们用暴力方法做,那就需要从str1中拿出一个,在str2中找,如果找到,就拿下一个继续找。找到最长序列,这只是从0开始的最长序列,还需要从1一直到n一直找下去,需要三层循环。因为动态规划是暴力的聪明算法,无非就是从str[1]到str[n]分别对应扫描一遍。如果出现相等就换一个继续,则定义f(x,y)表示 str1的前x个和str2的前y个的最长子序列。
b、推导公式分析如下
在这里插入图片描述

c、根据推导公式中有x-1,y-1,则需要计算出x=0; y=0的值,否则会出现负数。即f(0,y)=0; y=0到str2的长度。f(x,0)=0,x=0到str1的长度,代码如下:

 public String LCS (String s1, String s2) {
        String[][] f = new String[s1.length()+1][s2.length()+1];

        for( int i=0; i< s1.length()+1; i++ ){
            f[i][0] = "";
        }

        for( int i=0; i<=s2.length(); i++ ){
            f[0][i] = "";
        }

        for( int i=1; i<=s1.length(); i++ ){
            for( int j=1; j<=s2.length(); j++ ){
                if(s1.charAt(i-1)==s2.charAt(j-1)){
                    f[i][j] = f[i-1][j-1]+s1.charAt(i-1);
                } else {
                    if(f[i-1][j].length()>f[i][j-1].length()){
                        f[i][j] = f[i-1][j];
                    } else {
                        f[i][j] = f[i][j-1];
                    }
                }
            }
        }

        return f[s1.length()][s2.length()].length()==0? "-1":f[s1.length()][s2.length()];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值