代码随想录算法训练营第三十八天 | 509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

42 阅读4分钟

509. 斐波那契数

链接

题目链接

文章链接

第一想法

这道题应该是最简单的一道动态规划题,状态转移方程很容易就想出了arr[i] = arr[i - 1] + arr[i - 2],所以比较简单,代码如下

function fib(n: number): number {
  let arr: number[] = [0, 1]
  for (let i = 2; i <= n; i++) {
    arr[i] = arr[i - 1] + arr[i - 2]
  }
  return arr[n]
}

看完文章后的想法

由于这道题很简单,这里就先说说写动态规划题的步骤:

  1. 确定dp数组已经下标的含义
  2. 确定递推公式
  3. 如何对dp进行初始化
  4. 确定遍历顺序
  5. 举例查看遍历是否正确

这就是文章所介绍的步骤,也是我应该要学会的,那么我就拿这道题举例

  1. 确定dp数组已经下标的含义: dp[i]表示第i个斐波那契数
  2. 确定递推公式: 递推公式题目已经给出 F(n)=F(n-2)+F(n-1)
  3. 如何对dp进行初始化: 初始化只需把F(0)和F(1)列举出就行了
  4. 确定遍历顺序:因为值与它前两个值有关,所以是从前往后遍历的
  5. 举例查看遍历是否正确: 0 1 1 2 3

思考

这道题是最简单的一道DP题,这道题主要是属性动态规划的模板和思想。

70. 爬楼梯

链接

题目链接

文章链接

第一想法

这道题也是一道比较简单的题,但是dp数组有不同的含义,dp[i]的含义为爬到i层的方法数,所以这样就很容易想到递推公式:当前i层的方法数=i-1层的方法数+i-2层的方法数(因为可以一次爬1或2个台阶),代码如下:

function climbStairs(n: number): number {
  let arr: number[] = [1, 1]//初始化我把0设置为1是为了让arr[2]好计算
  for (let i = 2; i <= n; i++) {
    arr[i] = arr[i - 1] + arr[i - 2]
  }
  return arr[n]
}

看完文章的想法

文章的想法和我一样,不一样的是对于dp[0],其实dp[0]=0和dp[0]=1我感觉纠结意义不太大,因为可以初始化dp[1]和dp[2]这样就很好理解了,这里就不放置代码了,想看其他版本的代码可以去代码随想录种

思考

这道题如果能把dp数组的含义想出来就很容易了,其实也不算很难,对于dp[0]的含义其实在这道题意义不大,但是如果硬说还是dp[0]=0比较符合dp数组的含义

746. 使用最小花费爬楼梯

链接

文章链接

题目链接

第一想法

这道题还是先想dp数组是啥意思,不太好想,我觉得是走到当前楼梯所花费的费用+从这个楼梯走的费用,所以递推公式我写的是costs[i] = Math.min(costs[i - 1], costs[i - 2]) + cost[i],当前的costs等于i-1层楼梯的费用与i-2层楼梯费用的最小值之后再加上从这层楼梯往上走的费用

function minCostClimbingStairs(cost: number[]): number {
  let costs: number[] = [cost[0], cost[1]]//初始化 如果按照上面我的理解的话这个初始化就不太难理解
  for (let i = 2; i < cost.length; i++) {
    costs[i] = Math.min(costs[i - 1], costs[i - 2]) + cost[i]
  }
  return Math.min(costs[costs.length - 1], costs[costs.length - 2]) //因为要上到楼顶 所以要看一下楼顶-1层和楼顶-2层那个花费少
}

看完文章后的想法

文章的dp数组的含义和我的自己想的有所区别(我的想法是文章中拓展的写法),文章的想法是dp数组是到当前台阶的最小费用,所以初始化dp[0]和dp[1]都为0,同时递推公式为 costs[i] = Math.min(costs[i - 1] + cost[i - 1], costs[i - 2] + cost[i - 2]),含义为当前层的费用为i-1层的累积费用+i-1层的费用与i-2层的累积费用+i-2层的费用的最小值代码如下:

function minCostClimbingStairs(cost: number[]): number {
  let costs: number[] = [0, 0]
  for (let i = 2; i <= cost.length; i++) {//这里有等于号是因为让dp最后一个就是结果值
    costs[i] = Math.min(costs[i - 1] + cost[i - 1], costs[i - 2] + cost[i - 2])
  }
  return costs[costs.length - 1]
}

思考

这道题dp数组的含义不同,递推公式就不同,对于两种递推公式,还是文章写的比较好理解。

今日总结

今天耗时2小时,题都不算太难,主要是理解动态规划的思想以及初步尝试递推公式和dp数组。