LeetCode 热题 100 | 动态规划(一)

目录

1  70. 爬楼梯

1.1  基本思路

1.2  官方题解

2  118. 杨辉三角

3  198. 打家劫舍


菜鸟做题,语言是 C++

1  70. 爬楼梯

核心思想:把总问题拆解为若干子问题。

  • 总问题:上到 5 楼的方式有多少种
  • 子问题:上到 4 楼的方式有多少种、上到 3 楼的方式有多少种
  • 总问题 = 子问题 1 + 子问题 2

因为题目要求每次只能爬 1 或 2 个台阶,所以子问题只有两个。

1.1  基本思路

假设按照英国算法要爬 6 层楼,如下图所示:

使用一个名为 dp 的数组来存储爬到每一层楼的方式种数。

由于我们只能从 4 或 3 楼爬到 5 楼,因此爬到 5 楼的方式种数 = 爬到 4 楼的方式种数 + 爬到 3 楼的方式种数,即 dp[5] = dp[4] + dp[3],以此类推。

特别地,对于 0 楼和 1 楼,由于只有一种方式爬到它们,因此直接设为 1 即可。

很不幸,上述方法需要维护一个长为 n 的数组 dp,因此空间复杂度是 O(n),而这样会超出内存限制,下面来看官方题解的奇妙方法。

1.2  官方题解

由 1.1 节的分析可知,dp[5] 只与 dp[4] 和 dp[3] 有关。因此在第 5 时刻,我们只需要记住 dp[4] 和 dp[3] 即可。换句话说,就是通过忘记其他 dp 元素来节省内存空间。

如下图所示。我们设置变量 p、q、r 来分别存储 dp[i - 2]、dp[i - 1]、dp[i],并不断更新这些变量。

可以把 p、q、r 理解为一个滑动窗口,每次同时向后移动一格,以此忘记不再需要的 dp 元素。 

完整代码如下:

class Solution {
public:
    int climbStairs(int n) {
        int p = 0, q = 0, r = 1;
        for (int i = 0; i < n; ++i) {
            p = q;
            q = r;
            r = p + q;
        }
        return r;
    }
};

这个启动方式还是挺妙的:

int p = 0, q = 0, r = 1;

2  118. 杨辉三角

核心思想:把总问题拆解为若干子问题。

  • 总问题:第 i 行第 j 列元素的值
  • 子问题:第 i - 1 行第 j 列元素的值、第 i - 1 行第 j + 1 列元素的值
  • 总问题 = 子问题 1 + 子问题 2

模仿上述动图初始化 ans 数组:

vector<vector<int>> ans(numRows);
for (int i = 1; i <= numRows; ++i) {
    ans[i - 1].resize(i);
    ans[i - 1][0] = 1;
    ans[i - 1][i - 1] = 1;
}

就是把那一圈 “1” 先填了,虽然笨,但貌似不影响效率。

完整代码如下:

class Solution {
public:
    vector<vector<int>> generate(int numRows) {

        vector<vector<int>> ans(numRows);
        for (int i = 1; i <= numRows; ++i) {
            ans[i - 1].resize(i);
            ans[i - 1][0] = 1;
            ans[i - 1][i - 1] = 1;
        }

        for (int i = 2; i < numRows; ++i) {
            for (int j = 1; j < ans[i].size() - 1; ++j) {
                ans[i][j] = ans[i - 1][j - 1] + ans[i - 1][j];
            }
        }

        return ans;
    }
};

3  198. 打家劫舍

核心思想:把总问题拆解为若干子问题。

  • 总问题:打劫完第 i 家所获最大金额
  • 子问题:打劫完第 i - 2 家所获最大金额、打劫完第 i - 3 家所获最大金额
  • 总问题 = 子问题 1 + 子问题 2

Q:为什么只考虑打劫第 i - 2 家和第 i - 3 家?

A:假设 i = 5,如下图所示。对于第 i - 1 家,由于不能打劫相邻的两家,因此要想打劫第 i 家,就不能打劫第 i - 1 家。可以打劫第 i - 2 家或者第 i - 3 家,如情况一和情况二所示。对于第 i - 4 家,由于要使金额最大,因此肯定还会打劫第 i - 2 家,从而认为情况一等价于情况三。

综上,我们只需要考虑情况一和情况二即可。

同  70. 爬楼梯  的简化思路相同,我们同样可以只设置几个变量来存储历史打劫金额,而非使用一个 dp 数组。其中,h3 存储第 i - 3 家,h2 存储第 i - 2 家,h1 存储第 i - 1 家,h0 存储第 i 家。

完整代码如下:

class Solution {
public:
    int rob(vector<int>& nums) {

        int h3 = 0, h2 = 0, h1 = 0;
        int ans = INT_MIN;
        for (int i = 0; i < nums.size(); ++i) {
            int h0 = max(nums[i] + h3, nums[i] + h2);
            ans  = max(ans, h0);
            h3 = h2;
            h2 = h1;
            h1 = h0;
        }
        return ans;
    }
};

相关推荐

  1. LeetCode 100 动态规划专题解析

    2024-04-03 10:38:01       38 阅读
  2. LeetCode100】【动态规划】杨辉三角

    2024-04-03 10:38:01       40 阅读
  3. LeetCode100】【动态规划】单词拆分

    2024-04-03 10:38:01       38 阅读
  4. LeetCode100】【动态规划】零钱兑换

    2024-04-03 10:38:01       35 阅读
  5. LeetCode100】【多维动态规划】编辑距离

    2024-04-03 10:38:01       35 阅读
  6. leetcode100.零钱兑换(动态规划

    2024-04-03 10:38:01       21 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-03 10:38:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-03 10:38:01       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-03 10:38:01       82 阅读
  4. Python语言-面向对象

    2024-04-03 10:38:01       91 阅读

热门阅读

  1. CSS基础语法-黑马跟课笔记-供记录与查询

    2024-04-03 10:38:01       29 阅读
  2. PyTorch学习之:深入理解神经网络

    2024-04-03 10:38:01       32 阅读
  3. 24年2月-3月工作笔记整理(前端)

    2024-04-03 10:38:01       35 阅读
  4. 华为机试打卡 HJ102 字符统计

    2024-04-03 10:38:01       36 阅读
  5. ISBN信息查询api接口

    2024-04-03 10:38:01       36 阅读