Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 39 additions & 25 deletions problems/0123.买卖股票的最佳时机III.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,35 +193,49 @@ dp[1] = max(dp[1], dp[0] - prices[i]); 如果dp[1]取dp[1],即保持买入股
Java:

```java
class Solution { // 动态规划
// 版本一
class Solution {
public int maxProfit(int[] prices) {
// 可交易次数
int k = 2;

// [天数][交易次数][是否持有股票]
int[][][] dp = new int[prices.length][k + 1][2];

// badcase
dp[0][0][0] = 0;
dp[0][0][1] = Integer.MIN_VALUE;
dp[0][1][0] = 0;
dp[0][1][1] = -prices[0];
dp[0][2][0] = 0;
dp[0][2][1] = Integer.MIN_VALUE;

for (int i = 1; i < prices.length; i++) {
for (int j = 2; j >= 1; j--) {
// dp公式
dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
}
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] + prices[i]);
dp[i][3] = Math.max(dp[i - 1][3], dp[i][2] - prices[i]);
dp[i][4] = Math.max(dp[i - 1][4], dp[i][3] + prices[i]);
}

int res = 0;
for (int i = 1; i < 3; i++) {
res = Math.max(res, dp[prices.length - 1][i][0]);
return dp[len - 1][4];
}
}

// 版本二: 空间优化
class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
int[] dp = new int[5];
dp[1] = -prices[0];
dp[3] = -prices[0];

for (int i = 1; i < len; i++) {
dp[1] = Math.max(dp[1], dp[0] - prices[i]);
dp[2] = Math.max(dp[2], dp[1] + prices[i]);
dp[3] = Math.max(dp[3], dp[2] - prices[i]);
dp[4] = Math.max(dp[4], dp[3] + prices[i]);
}
return res;

return dp[4];
}
}
```
Expand Down
63 changes: 38 additions & 25 deletions problems/0188.买卖股票的最佳时机IV.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,41 +170,54 @@ public:
Java:

```java
class Solution { //动态规划
// 版本一: 三维 dp数组
class Solution {
public int maxProfit(int k, int[] prices) {
if (prices == null || prices.length < 2 || k == 0) {
return 0;
}

// [天数][交易次数][是否持有股票]
int[][][] dp = new int[prices.length][k + 1][2];

// bad case
dp[0][0][0] = 0;
dp[0][0][1] = Integer.MIN_VALUE;
dp[0][1][0] = 0;
dp[0][1][1] = -prices[0];
// dp[0][j][0] 都均为0
// dp[0][j][1] 异常值都取Integer.MIN_VALUE;
for (int i = 2; i < k + 1; i++) {
dp[0][i][0] = 0;
dp[0][i][1] = Integer.MIN_VALUE;
if (prices.length == 0) return 0;

// [天数][交易次数][是否持有股票]
int len = prices.length;
int[][][] dp = new int[len][k + 1][2];

// dp数组初始化
// 初始化所有的交易次数是为确保 最后结果是最多 k 次买卖的最大利润
for (int i = 0; i <= k; i++) {
dp[0][i][1] = -prices[0];
}

for (int i = 1; i < prices.length; i++) {
for (int j = k; j >= 1; j--) {
// dp公式
for (int i = 1; i < len; i++) {
for (int j = 1; j <= k; j++) {
// dp方程, 0表示不持有/卖出, 1表示持有/买入
dp[i][j][0] = Math.max(dp[i - 1][j][0], dp[i - 1][j][1] + prices[i]);
dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
}
}
return dp[len - 1][k][0];
}
}

int res = 0;
for (int i = 1; i < k + 1; i++) {
res = Math.max(res, dp[prices.length - 1][i][0]);
// 版本二: 空间优化
class Solution {
public int maxProfit(int k, int[] prices) {
if (prices.length == 0) return 0;

// [天数][股票状态]
// 股票状态: 奇数表示第 k 次交易持有/买入, 偶数表示第 k 次交易不持有/卖出, 0 表示没有操作
int len = prices.length;
int[][] dp = new int[len][k*2 + 1];

// dp数组的初始化, 与版本一同理
for (int i = 1; i < k*2; i += 2) {
dp[0][i] = -prices[0];
}

return res;
for (int i = 1; i < len; i++) {
for (int j = 0; j < k*2 - 1; j += 2) {
dp[i][j + 1] = Math.max(dp[i - 1][j + 1], dp[i - 1][j] - prices[i]);
dp[i][j + 2] = Math.max(dp[i - 1][j + 2], dp[i - 1][j + 1] + prices[i]);
}
}
return dp[len - 1][k*2];
}
}
```
Expand Down