Skip to content

动态规划

约 1182 字大约 4 分钟

2024-11-03

爬楼梯

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

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

int climbStairs(int n) {
        if (n == 0) {
            return 1;
        } else if (n == 1) {
            return 1;
        } else if (n == 2) {
            return 2;
        }
        int i = 3;
        int n1 = 2, n2 = 1, curr = 0;

        while (i <= n) {
            curr = n1 + n2;
            n2 = n1;
            n1 = curr;
            i++;
        }

        return curr;
    }

对于一阶楼梯只有走 1台阶 一个方法 f(1) = 1,对于二阶楼梯有 一个2阶 和 两个1阶 两种方法 f(2) = 2,对于三阶楼梯有 三个1阶 和 两个1阶一个2阶(两种组合) 三种方法 f(3) = 3,对于四阶楼梯有 四个1阶 两个2阶 两个1阶一个2阶(3种组合) 五种方法 f(4) = 5

类比推理可得 f(x) = f(x - 1) + f(x - 2)

最小花费爬楼梯

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

翻译:假设 cost 的长度是 n,可以理解为有 n + 1 阶楼梯要爬,第一步你可以选择从下标 0 或 1 开始,cost[i] 指的是从第 i 阶楼梯出发的价格,例如示例 1 你从第 0 阶台阶出发必须花费 10,从第 1 阶台阶出发则花费 15,你每次可以走一或二阶楼梯,比如说你从 0 阶出发可以到 1 阶或 2 阶楼梯。你的目的地是楼梯的顶层,示例 1 中你从第 3 阶楼梯出发要走 1 阶楼梯,从第 2 阶楼梯出发需要走 2 阶楼梯才可到达

示例 1:

输入:cost = [10,15,20]
输出:15
解释:你将从下标为 1 的台阶开始。
- 支付 15 ,向上爬两个台阶,到达楼梯顶部。
总花费为 15 。

示例 2:

输入:cost = [1,100,1,1,1,100,1,1,100,1]
输出:6
解释:你将从下标为 0 的台阶开始。
- 支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
- 支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
- 支付 1 ,向上爬一个台阶,到达楼梯顶部。
总花费为 6 。

解法(动态规划)

int minCostClimbingStairs(vector<int>& cost) {
    vector<int> dp(cost.size() + 1);// 划定一个比 cost 的长度加一的数组用于存放到达每一阶楼梯的最小花费,最后的 dp[cost.size()] 就是登顶所需的最小花费

    dp[0] = dp[1] = 0;// 题目表明可以从 0 和 1 阶出发,也就是无需消费
    for (int i = 2; i <= cost.size(); i++) {
        dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);// 到达第 i 阶的前置台阶只能是第 i - 1 和 i - 2 (每次能走一或二个台阶)。对于每一阶台阶的花费相当于到达前置台阶的价钱加上从前置台阶出发的价格
    }

    return dp[cost.size()];
}

不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

img

输入:m = 3, n = 7
输出:28

只能向下和向右行动。假设初始点为(1, 1),走到(2, 2)有两种方式;走到(3, 3)只能从(3, 2)或(2, 3)到达,那么到达(3, 3)的路线数为到达(3, 2)和(2, 3)的路线数的总和,即 f(i, j) = f(i - 1, j) + f(i, j - 1)。

对于该题,因为终点始终在右下角,可以求对于每一列到达最后一行的路线数量(或对于每一行到达最后一列的路线数量),对于第 i 列的最后一行的路线数都受第 i - 1 列最后一行的路线数的影响,即第 i + 1 列比第 i 列路线数多 所有行的数量

int uniquePaths(int m, int n) {
    vector<int> f(m, 1);

    for (int i = 1; i < n; ++i) {
        for (int k = 1; k < m; ++k) {
            f[k] += f[k - 1];
        }
    }

    return f[m - 1];
}