LeetCode系列之动态规划专题
1. 动态规划题目概述
https://leetcode-cn.com/tag/dynamic-programming/
B站视频讲解:
https://www.bilibili.com/video/BV18x411V7fm
https://www.bilibili.com/video/BV12W411v7rd
“选和不选”的方法,写出递推式,以便进一步分析。
2. 典型题目
2.1 不同的二叉搜索树
https://leetcode-cn.com/problems/unique-binary-search-trees/
有两种方法:1. 动态规划;2. 纯数学方法(看到这种输入为整数,输出为整数的题目,一般都有纯数学方法。关键看你数学功底了)。
- 动态规划
递推公式:G(n) = ∑G(i-1) • G(n-i),1 ≤ i ≤ n。
int numTrees(int n) { vector<int> G(n + 1, 0); G[0] = 1; G[1] = 1; for (int i = 2; i <= n; i++) { for (int j = 1; j <= i; j++) { G[i] += G[j - 1] * G[i - j]; } } return G[n]; }
vector初始化的部分,值得学习。
时间复杂度O(N2),空间复杂度O(N)。
int numTrees(int n) { vector<int> G(n + 1); G[0] = 1; G[1] = 1; for (int i = 2; i <= n; i++) { G[i] = getSumOfProduct(G, i); } return G[n]; } int getSumOfProduct(const vector<int>& G, int n) { int ret = 0; for (int i = 1; i <= n; i++) { ret += G[i - 1] * G[n - i]; } return ret; }
和上面代码完全相同,但是我觉得这么写,思路更清晰。
- 卡塔兰数
int numTrees(int n) { int64_t c = 1; for (int i = 0; i < n; i++) { c = 2 * (2 * i + 1) * c / (i + 2); } return static_cast<int>(c); }
注意c的类型必须是int64_t,防止乘法溢出。
时间复杂度O(N),空间复杂度O(1)。
2.2 零钱兑换
https://leetcode-cn.com/problems/coin-change/
int coinChange(vector<int>& coins, int amount) { const int MAX = amount + 1; vector<int> dp(amount + 1, MAX); dp[0] = 0; for (int i = 1; i <= amount; i++) { for (int coin : coins) { if (coin <= i) { dp[i] = min(dp[i], dp[i - coin] + 1); } } } return dp[amount] > amount ? -1 : dp[amount]; }
几个注意点:
- MAX不能简单实用INT_MAX,因为后面有dp[i] + 1,导致int溢出。官方解答里给的amount + 1,就很巧妙。
- 注意判断coin ≤ i
时间复杂度O(SN),空间复杂度O(N)。N是总金额,S是硬币面值数。
2.3 最大正方形
https://leetcode-cn.com/problems/maximal-square/
最关键的,还是找出递推式,官方题解如下:
以下代码有两点说明:
- 注意vector的初始化,第一个参数是size,第二个参数是初始值。
- 重载了一个三参数版本的min函数。
int maximalSquare(vector<vector<char>>& matrix) { if (matrix.size() == 0 || matrix[0].size() == 0) { return 0; } int maxSide = 0; int rows = matrix.size(); int columns = matrix[0].size(); vector<vector<int>> dp(rows, vector<int>(columns, 0)); for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { if (matrix[i][j] == '1') { if (i == 0 || j == 0) { dp[i][j] = 1; } else { dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1; } maxSide = max(maxSide, dp[i][j]); } } } int maxSquare = maxSide * maxSide; return maxSquare; } int min(int a, int b, int c) { return std::min(std::min(a, b), c); }
时间复杂度O(MN),空间复杂度O(MN)。假设矩阵为M行N列。
类似扩展题目
https://leetcode-cn.com/problems/count-square-submatrices-with-all-ones/
2.4 最小路径和
https://leetcode-cn.com/problems/minimum-path-sum/
int minPathSum(vector<vector<int>>& grid) { if (grid.size() == 0 || grid[0].size() == 0) { return 0; } int rows = grid.size(); int columns = grid[0].size(); vector<vector<int>> dp(rows, vector<int>(columns)); dp[0][0] = grid[0][0]; for (int i = 1; i < rows; i++) { dp[i][0] = grid[i][0] + dp[i-1][0]; } for (int j = 1; j < columns; j++) { dp[0][j] = grid[0][j] + dp[0][j-1]; } for (int i = 1; i < rows; i++) { for (int j = 1; j < columns; j++) { dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]; } } return dp[rows-1][columns-1]; }
时间复杂度O(MN),空间复杂度O(MN)。假设矩阵为M行N列。
2.5 最佳买卖股票的时机含冷冻期(股票问题汇总,见文末总结)
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/
2.6 单词拆分
https://leetcode-cn.com/problems/word-break/
https://leetcode-cn.com/problems/word-break-ii/
2.7 爬楼梯
https://leetcode-cn.com/problems/climbing-stairs/
int climbStairs(int n) { int p = 0, q = 1, r = 1; for (int i = 1; i < n; i++) { p = q; q = r; r = p + q; } return r; }
题目比较简单,所以尽量把初值设置的巧妙一些,减少不必要的卫语句。
时间复杂度O(N),空间复杂度O(1)。
2.8 最大矩形
https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
https://leetcode-cn.com/problems/maximal-rectangle/
2.9 分割等和子集
https://leetcode-cn.com/problems/partition-equal-subset-sum/
2.10 不同路径
https://leetcode-cn.com/problems/unique-paths/
3. 总结
对于动态规划题目,最重要的是找出递归式。然后用记忆化技术,将中间计算结果保存。
股票问题汇总:
- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/
- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/
- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/
- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/
- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/
- https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/
- https://leetcode-cn.com/problems/gu-piao-de-zui-da-li-run-lcof/