• 动态规划题: 统计每个月兔子的总数


    大家好,我是前端西瓜哥,今天来做动态规划

    描述

    有一种兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子。比如某只兔子第 3 个月出生,那么它第 5 个月开始会每个月生一只兔子。

    一月的时候有一只兔子,假如兔子都不死,问第n个月的兔子总数为多少?

    示例 1:

    输入:3
    输出:2
    
    • 1
    • 2

    示例 2:

    输入:6
    输出:8
    
    • 1
    • 2

    题解

    解法是动态规划。

    兔子其实有两种状态:

    1. 可以不停生的兔子

    2. 刚生出来的兔子,它会在出生的那个月以及下一个月无法生兔子,下下个月才能生兔子。比如 3 月出生,5月才能生兔子(转换为状态 1)

    状态有两种,我们将动态转移表就要声明成 number[n][2] 了,表示第 n 个月的两种状态兔子的数量。

    dp[i][0] 表示可以一直生的兔子,dp[i][1] 表示刚出生的兔子。

    一开始我其实设计的是三种状态(可以一直生、出生第 1 天、出生第 2 天),但发现并没有太大必要,因为我发现变成不停生状态可以消耗当前月份,并不需要转换后立即就生兔子。当然三种状态也不是不行,但需要调整一下代码。

    这种 状态有多种,且它们之间会发生转换 的情况,在动态规划中还是比较常见的,比如 “198.打家劫舍”、“714. 买卖股票的最佳时机含手续费”,建议多练练这些题。

    “打家劫舍” 有 2 种状态:打劫了当前这家、没打劫当前这家。

    买卖股票的最佳时机含手续费” 有 2 种状态:持有状态、不持有状态。

    状态转移方程为:

    dp[i][0] = dp[i-1][0] + dp[i-1][1];
    dp[i][1] = dp[i-1][0];
    
    • 1
    • 2

    状态转移结束后,我们将两种状态的兔子数量加起来,就得到了所有的兔子数量。

    代码实现为:

    function rabbitSum(n: number) {
      const dp: number[][] = new Array(n + 1);
      for (let i = 0; i < dp.length; i++) {
        dp[i] = [0, 0];
      }
      // dp[i][0] 可以一直生
      // dp[i][1] 刚出生的兔子
    
      dp[1][1] = 1;
    
      for (let i = 2; i <= n; i++) {
        dp[i][0] = dp[i-1][0] + dp[i-1][1];
        dp[i][1] = dp[i-1][0];
      }
    
      return dp[n][0] + dp[n][1];
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    结尾

    动态规划还是要学习套路,然后多练习,才能较好地掌握。动态规划套路我以后会再写文章。

    我是前端西瓜哥,欢迎关注我,学习更多前端知识。

  • 相关阅读:
    【云原生 | Kubernetes 系列】K8s 实战 如何给应用注入数据 II 将pod数据传递给容器
    Laravel9版本的CMS出现Invalid datetime format异常
    中国交通标志牌数据集TT1OOK中的类别ID及其图标罗列以及含义详细介绍
    【Linux系统管理】05 常用命令 & 06 vim编辑器
    JPA Audit and Envers
    Linux 并发与竞争(二)
    Java如何从字符串中提取数字
    Zabbix最新6.2安装及使用!
    IP数据报的发送和转发过程
    AIGC:【LLM(一)】——LoRA微调加速技术
  • 原文地址:https://blog.csdn.net/fe_watermelon/article/details/127460377