地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/
我写的题解地址:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/bao-li-mei-ju-dong-tai-gui-hua-chai-fen-si-xiang-b/
Java 代码:
public class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
if (len < 2) {
return 0;
}
int res = 0;
// 表示在当前位置之前的最小值,假设修正法(打擂台法)
int minVal = prices[0];
// 注意:这里从 1 开始
for (int i = 1; i < len; i++) {
res = Math.max(res, prices[i] - minVal);
minVal = Math.min(minVal, prices[i]);
}
return res;
}
}
C++ 代码:
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
int maxProfit(vector<int> &prices) {
// 特判
int size = prices.size();
if (size == 0) {
return 0;
}
int minPrice = prices[0];
int res = 0;
for (int i = 1; i < size; i++) {
res = max(res, prices[i] - minPrice);
minPrice = min(minPrice, prices[i]);
}
return res;
}
};
复杂度分析:
- 时间复杂度:O(N)O(N)O(N)
- 空间复杂度:O(1)O(1)O(1)
使用标准动态规划的写法
题目中关键的地方:
1、只交易一次。这里的“交易”指的是“买入和卖出一支股票”,即发生一次交易得用 2 天时间;
2、如果股价是这样:[5, 4, 3, 2, 1] 先买后卖一定亏钱,全程不交易即可。
- 定义状态:
dp[i][j]表示[0, i]子区间里交易一次能够获得的最大利润。
说明:1、这里 j 只有两个取值:
0:用户手上不持股所能获得的最大利润,特指卖出股票以后的不持股,不是指没有进行过任何交易的不持股;
1:用户手上持股所能获得的最大利润。
- 状态转移方程:
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i])
dp[i][1] = max(dp[i - 1][1], -prices[i])
- 初始化:
dp[0][0] = 0,dp[0][1] = -prices[0]
说明:第 0 天不持股的时候,显然没有交易过,因此利润为 0;第 0 天持股的时候,显然只购买了一股,因此利润为 -prices[0];
- 输出:
dp[len - 1][0],输出一定是最后一天不持股的情况。我们定义的状态是有前缀性质的,因此只要把最后一天的状态输出即可。
Java 代码:
public class Solution {
// 动态规划
public int maxProfit(int[] prices) {
int len = prices.length;
if (len < 2) {
return 0;
}
// 交易的不持股
// 1:用户手上持股所能获得的最大利润
// 注意:因为题目限制只能交易一次,因此状态只可能从 1 到 0,不可能从 0 到 1
//
int[][] dp = new int[len][2];
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i < len; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
}
return dp[len - 1][0];
}
}
状态压缩1:使用滚动数组
Java 代码:
public class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
if (len < 2) {
return 0;
}
int[][] dp = new int[2][2];
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i < len; i++) {
dp[i & 1][0] = Math.max(dp[(i - 1) & 1][0], dp[(i - 1) & 1][1] + prices[i]);
dp[i & 1][1] = Math.max(dp[(i - 1) & 1][1], -prices[i]);
}
return dp[(len - 1) & 1][0];
}
}
状态压缩 2:直接把第 1 行压缩了
Java 代码:
public class Solution {
public int maxProfit(int[] prices) {
int len = prices.length;
if (len < 2) {
return 0;
}
int[] dp = new int[2];
dp[0] = 0;
dp[1] = -prices[0];
for (int i = 1; i < len; i++) {
dp[0] = Math.max(dp[0], dp[1] + prices[i]);
dp[1] = Math.max(dp[1], -prices[i]);
}
return dp[0];
}
}
- 差分数组。
本文详细解析了如何在给定的股票价格数组中找到最佳的买卖时机以获取最大利润。通过直观的假设修正法(打擂台法)和标准动态规划方法,提供了Java和C++的实现代码,同时对比了不同状态压缩技巧对代码简洁性和效率的影响。
&spm=1001.2101.3001.5002&articleId=103772951&d=1&t=3&u=d320aeb797114f11b188445f93203c54)
3242

被折叠的 条评论
为什么被折叠?



