算法训练 Day 38

写在前头
如果说大厂笔、面试题有迹可循的话,那最爱考的就是dfs、bfs和动规了,今天开始做动规的专项训练,它值得一个开场白。一刷LeetCode初遇动规的时候,是看的代码随想录卡哥的背包问题,卡哥将捉摸不定的动规题目总结出了一个模板,非常适合初学动规的小伙伴们去学习、揣摩,不要觉得背模板掉价,咱普通人写代码,就是一边抄一边写,抄多了,那些框架和手法就成自己的东西了。
代码随想录——动态规划理论基础

LeetCode 509. 斐波那契数

题目链接:509. 斐波那契数

思路:依据代码随想录总结的动态规划五部曲,分别是:

  1. 确定dp数组以及下标的含义;
  2. 确定递推公式;
  3. dp数组初始化;
  4. 确定遍历顺序;
  5. 举例推导dp数组。

再结合这道题,首先我们可以不使用dp数组,使用滚动的两个数来代替(类似滚动数组的思想);
递推公式在题目中已经给出: F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n) = F(n - 1) + F(n - 2) F(n)=F(n1)+F(n2),所以当前数就是它的前两个数之和;
初始化也在题目中给出,第一个数字是0,第二个数字是1;
从前向后遍历n次;
输出结果。

Python版本:

class Solution:
    def fib(self, n: int) -> int:
        a, b = 0, 1
        for _ in range(n):
            a, b = a+b, a
            
        return a

时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( 1 ) O(1) O(1)

go版本:

func fib(n int) int {
    a, b := 0, 1
    for i:=0; i<n; i++ {
        a, b = a+b, a
    }
    return a
}

LeetCode 70. 爬楼梯

题目链接:70. 爬楼梯

思路:重复记忆一下我们的动态规划五部曲:

  1. 确定dp数组以及下标的含义;
  2. 确定递推公式;
  3. dp数组初始化;
  4. 确定遍历顺序;
  5. 举例推导dp数组。

dp数组就是爬上第n个台阶有几种方法;
递推公式根据题目场景想一下,想爬上第n阶台阶的话,只能从第n-1阶爬上来,或是从第n-2阶爬上来这两种情况,所以爬上第n阶台阶的方法就是能爬到第n-1阶的方法数加能爬到第n-2阶的方法数之和,本题的递推公式: F ( n ) = F ( n − 1 ) + F ( n − 2 ) F(n) = F(n - 1) + F(n - 2) F(n)=F(n1)+F(n2),与斐波那契数列恰好一致;
初始值情况为,爬上第1阶台阶有1种方法,爬上第2阶台阶有2种方法;
从前向后,从索引2遍历至n-1;
返回dp数组的最后一个值。

Python版本:

class Solution:
    def climbStairs(self, n: int) -> int:
        a = 1
        b = 2
        if n<=3:
            return n

        for _ in range(n-2):
            b, a = a+b, b

        return b

时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( 1 ) O(1) O(1)

go版本(使用dp数组):

func climbStairs(n int) int {
    if n<=3 {
        return n
    }
    dp := make([]int, n)
    dp[0] = 1
    dp[1] = 2
    for i:=2; i<n; i++ {
        dp[i] = dp[i-1] + dp[i-2]
    }

    return dp[n-1]
}

LeetCode

题目链接:

思路:重要的思想记三遍:

  1. 确定dp数组以及下标的含义;
  2. 确定递推公式;
  3. dp数组初始化;
  4. 确定遍历顺序;
  5. 举例推导dp数组。

dp数组就是爬上第n个台阶的最低花费,但本题有个大坑,要越过最后一阶台阶才算爬上楼梯顶部,所以dp数组要比cost数组的长度加1,表示越过cost数组的最后一个台阶爬上顶部;
递推公式根据题目场景想一下,想爬上第n阶台阶的话,只能从第n-1阶爬上来,或是从第n-2阶爬上来这两种情况,所以爬上第n阶台阶的最低花费就是从上述两种情况中选一个花费低的,本题的递推公式:
d p [ i ] = m i n ( d p [ i − 1 ] + c o s t [ i − 1 ] , d p [ i − 2 ] + c o s t [ i − 2 ] ) dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2]) dp[i]=min(dp[i1]+cost[i1],dp[i2]+cost[i2])
初始值情况为,可以选择从从下标为 0 或下标为 1 的台阶开始爬楼梯,所以 dp[0] 和 dp[1] 都是0;
从前向后,从索引2遍历至n,因为要越过最后一阶台阶,可以想象成 cost 后面才是楼梯顶部;
返回dp数组的最后一个值。

Python版本:

class Solution:
    def minCostClimbingStairs(self, cost: List[int]) -> int:
        n = len(cost)
        if n==2:
            return min(cost)

        dp = [0] * (n+1)
        for i in range(2, n+1):
            dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2])

        return dp[-1]

时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( n ) O(n) O(n)

go版本:

func minCostClimbingStairs(cost []int) int {
    if len(cost)==2 {
        return min(cost[0], cost[1])
    }
    dp := make([]int, len(cost)+1)
    for i:=2; i<=len(cost); i++ {
        dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2])
    }
    fmt.Println(dp)
    return dp[len(dp)-1]
}

func min(i, j int) int {
    if i<j {
        return i
    } else {
        return j
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值