• 【动态规划】爬楼梯爬的不仅仅是楼梯


    深度思考爬楼梯问题,抽取一般过程,目标是对其变式题也能认出并且求解

    一、题目描述

    假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

    https://leetcode.cn/problems/climbing-stairs/description/

    示例:

    在这里插入图片描述

    二、动态规划过程详解

    思考一:为什么可以动态规划?

    动态规划是指大规模问题,可以由它的小规模问题通过动态规划方程解出,而对本题来说,到达第 i 阶台阶的方案数可以由到达第 i-1 和 第 i-2的方案数求出,动态规划方程为:

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

    解释:

    上述动态规划方程中,dp 表示到达第 i 阶台阶的方案数,可以由第 i-1 阶台阶走一步到达第 i 阶台阶,也可由第 i-2 阶台阶走两步到达第 i 阶台阶,所以可写出如上的动态规划方程。

    思考二: 如何初始化

    dp[1] = 1;
    dp[2] = 2; 
    
    • 1
    • 2

    解释:

    状态转移方程决定了初始化的值为 dp[1] 和 dp[2] (dp[i] = dp[i-1] + dp[i-2])

    从第 0 台台阶迈一步到达第 1 阶台阶,因此到达第 1 阶台阶的方案有 1 个,同理,得到 dp[2] (由第 1 阶台阶迈一步 和 由第 0 阶台阶迈两步)

    三、代码

    class Solution {
         // 爬楼梯
        public int climbStairs(int n) {
            if(n == 1){
                return 1;
            } else if(n == 2){
                return 2;
            }
            int dp[] = new int[n+1];
            dp[1] = 1;
            dp[2] = 2;
            for(int i=3; i<n+1; i++){
                dp[i] = dp[i-1] + dp[i-2];
            }
            return dp[n];
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    四、看变式 —— 统计构造好字符串的方案数

    给你整数 zero ,one ,low 和 high ,我们从空字符串开始构造一个字符串,每一步执行下面操作中的一种:

    • 将 ‘0’ 在字符串末尾添加 zero 次。
    • 将 ‘1’ 在字符串末尾添加 one 次。

    以上操作可以执行任意次。

    如果通过以上过程得到一个 长度 在 low 和 high 之间(包含上下边界)的字符串,那么这个字符串我们称为 好 字符串。

    https://leetcode.cn/problems/count-ways-to-build-good-strings/description/

    在这里插入图片描述

    思路:

    让我们来看一下,本题和爬楼梯的区别和联系

    • 返回值上: 它们都是求方案数,爬楼梯是求到某个值的方案数,而本题是求到某个范围的方案数,那么爬楼梯只需要返回 dp[n],本题返回 dp[low] + dp[low+1] + … + dp[high] 。
    • 状态转移方程上:
    dp[i] = dp[i - zero] + dp[i - one];
    
    • 1
    代码:
        // 2466. 统计构造好字符串的方案数
        public int countGoodStrings(int low, int high, int zero, int one) {
            int mod = (int)(1e9 + 7);
            int[] dp = new int[high + 1];
            // 初始化
            int step1 = Math.min(zero, one);
            int step2 = Math.max(zero, one);
            dp[step1] = 1;
            dp[step2] = step2%step1==0 ? 2 : 1; // 走到 step2 的可能方案(直接走到step2、每次蹦跶step1直到蹦跶到step2)
    
            // 遍历
            for(int i=step1+1; i<=high; i++){
                if(i > step2) { // 可以由 i - step1 和 i - step2 到达
                    dp[i] = (dp[i - step1] + dp[i - step2]) % mod;
                } else if(i < step2){  // 只可以由 i - step1 到达
                    dp[i] = dp[i - step1];
                }
            }
            int res = 0;
            for(int i=low; i<=high; i++){ // 计算结果,在 low ~ high 之间的方案数
                res = (res + dp[i]) % mod;
            }
            return res;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    <总结> : 对一个问题,我们的求解关键是应该是抽丝剥茧,把问题捋清楚。像本文中的第二种变式题,它题目里的什么 0 1 就是误导,和 0 和 1 没关系,不要被误导,就是两种 step,给两种走不同 step 的方式!!!翻译过来就是走楼梯问题 ~~ 大家有不明白的欢迎评论区和我交流~~

  • 相关阅读:
    Dubbo Admin修改注册中心为Nacos 以及Nacos整合Dubbo
    PE文件解析(1):Dos头与NT头
    ESP8266-Arduino编程实例-SHT21温度湿度传感器驱动
    自行车无级变速器设计
    mysql高级刷题-01-求项目子任务分组计算
    SigmaStudio定时器实验1
    安装K8s基础环境软件(二)
    Spark Optimizer 规则下的 BUG 排查与修复全记录
    商家WiFi小程序-2022年火爆副业轻创业项目
    数据加密和BCrypt哈希算法应用 | StartDT Tech Lab 15
  • 原文地址:https://blog.csdn.net/liuwanqing233333/article/details/128200396