动态规划
打家劫舍
打家劫舍
dp[i] = (dp[i - 2] + nums[i], dp[i - 1])
打家劫舍II
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,能够偷窃到的最高金额。
去除头和去除尾,用打家劫舍1的方法求两次,求最大值就可以
打家劫舍 III
在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。
计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。
class Solution {
public:
int rob(TreeNode* root) {
if (!root) return 0;
if (!root->left && !root->right) {
return root->val;
}
if (cache[root]) {
return cache[root];
}
int rootval = root->val;
if (root->left) rootval += rob(root->left->left) + rob(root->left->right); // 不偷root->left
if (root->right) rootval += rob(root->right->left) + rob(root->right->right); // 不偷root->right
int nonrootval = rob(root->left) + rob(root->right); // 不偷root
int res = max(rootval, nonrootval);
cache[root] = res; // 记录当前节点为根,能盗取的最大金额
return res;
}
private:
unordered_map<TreeNode*, int> cache;
int res = 0;
};
买股票问题
买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
- 示例 1:
- 输入:[7,1,5,3,6,4]
- 输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
初始时,将第一天作为买入的时候,后面遍历数组,当大于买入价格时,记录差值。当小于买入价格时,更新买入时间。
买卖股票的最佳时机II
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
- 示例 1:
- 输入: [7,1,5,3,6,4]
- 输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
class Solution {
public:
int maxProfit(vector<int>& prices) {
// dp[i][0] 表示第i天持有股票所得现金。
// dp[i][1] 表示第i天不持有股票所得最多现金
int len = prices.size();
vector<vector<int>> dp(len, vector<int>(2, 0));
dp[0][0] -= prices[0];
dp[0][1] = 0;
// 持有股票需要和持有股票的状态比较
// 没买股票需要和没买股票的状态比较
for (int i = 1; i < len; i++) {
// dp[i - 1][0]: 继续持有股票,dp[i - 1][1] - prices[i]:第i天买入股票
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
// dp[i - 1][1]:继续不买股票,dp[i - 1][0] + prices[i]:第i天卖出股票
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
}
return dp[len - 1][1];
}
};
买卖股票的最佳时机III
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
- 示例 1:
- 输入:prices = [3,3,5,0,0,3,1,4]
- 输出:6 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3。
class Solution {
public:
int maxProfit(vector<int>& prices) {
// dp[i][0]: 没有任何操作
// dp[i][1]: 第一次持有股票
// dp[i][2]: 第一次不持有股票
// dp[i][3]: 第二次持有股票
// dp[i][4]: 第二次不持有股票
int len = prices.size();
// 第0天第二次买入操作,初始值应该是多少呢?应该不少同学疑惑,第一次还没买入呢,怎么初始化第二次买入呢?
// 第二次买入依赖于第一次卖出的状态,其实相当于第0天第一次买入了,第一次卖出了,然后再买入一次(第二次买入),那么现在手头上没有现金,只要买入,现金就做相应的减少。
// 所以第二次买入操作,初始化为:dp[0][3] = -prices[0];
vector<vector<int>> dp(len, vector<int>(5, 0));
dp[0][1] = dp[0][3] = -prices[0];
// dp[0][0] = dp[0][1] = dp[0][3] = 0;
// 持有股票需要和持有股票的状态比较
// 没买股票需要和没买股票的状态比较
for (int i = 1; i < len; i++) {
dp[i][0] = dp[i - 1][0];
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
}
return max({dp[len - 1][0], dp[len - 1][2], dp[len - 1][4]});
}
};
买卖股票的最佳时机IV
给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
- 示例 1:
- 输入:k = 2, prices = [2,4,1]
- 输出:2 解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2。
和Ⅲ一样
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
if (prices.size() == 0) return 0;
// dp[i][0]: 没有任何操作
// dp[i][2*k-1]: 第k次持有股票
// dp[i][2*k]: 第k次不持有股票
vector<vector<int>> dp(prices.size(), vector<int>(2 * k + 1, 0));
for (int i = 1; i < 2 * k + 1; i += 2) dp[0][i] = -prices[0];
for (int i = 1; i < prices.size(); i++) {
for (int j = 1; j < 2 * k + 1; j += 2) {
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1] - prices[i]);
dp[i][j + 1] = max(dp[i - 1][j + 1], dp[i - 1][j] + prices[i]);
}
}
return dp[prices.size() - 1][2 * k];
}
};