LeetCode学习笔记——初学动态规划

个人博客:The Blog Of WaiterXiaoYY 欢迎来互相交流学习。

今天,开始接触到动态规划问题,现在我对动态规划还没有一个完整的认识,更不用说掌握了,

目前我对动态规划的理解是,

在递归的过程中,我们可能会进行对一个数进行重复递归,这样子就导致时间复杂度呈指数增长,

比如:

斐波那契数列中,

我们知道 fib(n) = {1, 1, 2, 3 , 5, 8,……}, 这里举个例子,假如我们还不知道 fib(5) 是多少,

如果我们要算 fib(5) ,按照我们递归的思维,我们会这样做:

public int fib(int n) {
	if(n == 1 || n == 2)
		return 1;
	return fib(n - 1) + fib(n - 2);
}

内在流程是这样子的:

在这里插入图片描述

其实在运算的过程中,我们重复运算了 fib(3)

这时候如果我们想改进算法的话,是不是可以把 fib(3) 的值存起来

当下面某一次递归到 fib(3) 的时候,我们就可以直接用了?

改进上面那个算法后,长这个样子:

public int fib(int n) {
    //判断特殊值
    if(n == 1 || n == 2)
        return 1;
    //申请一个数组来保存算过的值
    int []dp = new int[n + 1]; 
    //初始我们前面的值,如果这个值没有初始化是没有规律可行的
    dp[1] = 1;
    dp[2] = 1;
    for(int i = 3; i <= n; i++) {
        dp[i] = dp[n - 1] + dp[n - 2];
    }
    return dp[n];
}

这个就是我初步认识的动态规划。


在leetcode里面有几道类似这样的题,哦不,不是类似,方法感觉就是一模一样的(狗头报命)


一. 青蛙跳台阶问题

一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。


示例 1:

输入:n = 2
输出:2

示例 2:

输入:n = 7
输出:21

解题思路

这道题可以分为两part,

第一先是考虑如何求出跳上n级台阶有多少种跳法,

然后再考虑对结果怎么取模;

这道题有个隐藏的条件没有给出来,就是 n == 0 的时候,结果应该是等于1的,

别问我怎么知道的(都是泪)。

跳台阶,有两种方法,一种跳一级,一种跳两级,

n == 1的时候,只有一种跳法,

n == 2 的时候,有两种跳法

  • 每次都跳一级,跳两次

  • 一次跳两级

这时候我们来看看 n == 3

n为3的时候,是可以分为子问题进行考虑的,

比如,青蛙是从哪一级跳到第三级的,

有可能是从第一级,直接跳两级,

有可能是从第二级,直接跳一级,

什么?有可能从第一级,每一次跳一级?

这种情况其实就是在第二级跳到第三级。

那青蛙是怎么跳到第二级或者第一级,我们已经讨论过了,

问题拆解完毕!

这样子,我们就知道,跳到 n 级,其实是跟怎么跳到 n - 1n - 2有关,

那这就是递归的思想,

f(n) = f(n - 1) + f(n - 2)

这就跟上面的斐波那契数列一模一样了。

利用动态规划优化一下,而且这道题用动态规划才能AC,因为递归进去,会超时。

第二步,是需要我们将答案取模,

我一开始这样做的:

return dp[n] % 1000000007;

结果打脸,因为如果针对结果取模的话,数组里面除的数就会超出范围了。


代码
class Solution {
    public int numWays(int n) {
        //判断特殊值
        if(n == 0 || n == 1)
            return 1;
        //申请一个数组记录已经计算后对应的值
        int []dp = new int[n + 1];
        //初始值,n == 2情况下的值必须作为初始值
        dp[0] = 1;
        dp[1] = 1;
        dp[2] = 2;
        for(int i = 2; i <= n; i++) {
            //对结果进行取模后再存入数组
            dp[i] = (dp[i - 1] + dp[i -2]) % 1000000007;
        }
        return dp[n] ;
    }
}

二. 爬楼梯问题

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

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

**注意:**给定 n 是一个正整数。


示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例 2:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

解题思路

这道题和青蛙的题目是一样的,只不过人换成了青蛙,台阶换成了楼梯

直接上代码


代码
class Solution {
    public int climbStairs(int n) {
        if(n == 0 || n == 1)
            return 1;
        int []dp = new int[n + 1];
        dp[0] = 1;
        dp[1] = 1;
        dp[2] = 2;
        for(int i = 2; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i -2];
        }
        return dp[n] ;
    }   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值