第九章 动态规划part08
股票问题是一个动态规划的系列问题,前两题并不难,第三题有难度。
121. 买卖股票的最佳时机
视频讲解:https://www.bilibili.com/video/BV1Xe4y1u77q
class Solution {
public int maxProfit(int[] prices) {
// 找到一个最小的购入点
int low = Integer.MAX_VALUE;
// res不断更新,直到数组循环完毕
int res = 0;
for(int i = 0; i < prices.length; i++){
low = Math.min(prices[i], low);
res = Math.max(prices[i] - low, res);
}
return res;
}
}
122.买卖股票的最佳时机II
视频讲解:https://www.bilibili.com/video/BV1D24y1Q7Ls
// 动态规划
class Solution
// 实现1:二维数组存储
// 可以将每天持有与否的情况分别用 dp[i][0] 和 dp[i][1] 来进行存储
// 时间复杂度:O(n),空间复杂度:O(n)
public int maxProfit(int[] prices) {
int n = prices.length;
int[][] dp = new int[n][2]; // 创建二维数组存储状态
dp[0][0] = 0; // 初始状态
dp[0][1] = -prices[0];
for (int i = 1; i < n; ++i) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); // 第 i 天,没有股票
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); // 第 i 天,持有股票
}
return dp[n - 1][0]; // 卖出股票收益高于持有股票收益,因此取[0]
}
}
123.买卖股票的最佳时机III
这道题一下子就难度上来了,关键在于至多买卖两次,这意味着可以买卖一次,可以买卖两次,也可以不买卖。
视频讲解:https://www.bilibili.com/video/BV1WG411K7AR
// 版本一
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
// 边界判断, 题目中 length >= 1, 所以可省去
if (prices.length == 0) return 0;
/*
* 定义 5 种状态:
* 0: 没有操作, 1: 第一次买入, 2: 第一次卖出, 3: 第二次买入, 4: 第二次卖出
*/
int[][] dp = new int[len][5];
dp[0][1] = -prices[0];
// 初始化第二次买入的状态是确保 最后结果是最多两次买卖的最大利润
dp[0][3] = -prices[0];
for (int i = 1; i < len; i++) {
dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
}
return dp[len - 1][4];
}
}
// 版本二: 空间优化
class Solution {
public int maxProfit(int[] prices) {
int[] dp = new int[4];
// 存储两次交易的状态就行了
// dp[0]代表第一次交易的买入
dp[0] = -prices[0];
// dp[1]代表第一次交易的卖出
dp[1] = 0;
// dp[2]代表第二次交易的买入
dp[2] = -prices[0];
// dp[3]代表第二次交易的卖出
dp[3] = 0;
for(int i = 1; i <= prices.length; i++){
// 要么保持不变,要么没有就买,有了就卖
dp[0] = Math.max(dp[0], -prices[i-1]);
dp[1] = Math.max(dp[1], dp[0]+prices[i-1]);
// 这已经是第二次交易了,所以得加上前一次交易卖出去的收获
dp[2] = Math.max(dp[2], dp[1]-prices[i-1]);
dp[3] = Math.max(dp[3], dp[2]+ prices[i-1]);
}
return dp[3];
}
}