leetcode 121. 买卖股票的最佳时机
题目链接:买卖股票的最佳时机
本题股票只能买卖一次。
方法一:贪心
class Solution {
public:
int maxProfit(vector<int>& prices) {
int low = INT_MAX;
int result = 0;
for (int i = 0; i < prices.size(); i++) {
low = min(low, prices[i]); // 取最左最小价格
result = max(result, prices[i] - low); // 直接取最大区间利润
}
return result;
}
};
时间复杂度:O(n)
空间复杂度:O(1)
方法二:动态规划
- 确定dp数组以及下标的含义
dp[i][0] 表示第i天持有股票所得最多现金,
dp[i][1] 表示第i天不持有股票所得最多现金 - 确定递推公式
(1)第i天持有股票,dp[i][0]可以由两个状态推出:
- 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 dp[i - 1][0]
- 第i天买入股票,所得现金就是买入今天的股票后所得现金 -prices[i]
则dp[i][0] = max(dp[i - 1][0], -prices[i])
(2)第i天不持有股票,dp[i][1]由两个状态推出来:
- 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 dp[i - 1][1]
- 第i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金 prices[i] + dp[i - 1][0]
则dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
- dp数组初始化
dp[0][0]表示第0天持有股票,所以dp[0][0] -= prices[0]
dp[0][1]表示第0天不持有股票,所以dp[0][1] = 0
- 确定遍历顺序
dp[i]都是由dp[i - 1]推导出来,所哟从前向后遍历 - 举例推导dp数组
输入[7,1,5,3,6,4],
dp[i][0]:-7 -1 -1 -1 -1 -1
dp[i][1]: 0 0 4 4 5 5
dp[5][1]是最终结果,因为不持有股票状态所得金钱一定比持有股票状态得到的多
版本一:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
if (len == 0) return 0;
vector<vector<int>> dp(len, vector<int>(2));
dp[0][0] -= prices[0];
dp[0][1] = 0;
for (int i = 1; i < len; i++) {
dp[i][0] = max(dp[i - 1][0], -prices[i]);
dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
}
return dp[len - 1][1];
}
};
时间复杂度:O(n)
空间复杂度:O(n)
版本二:
dp[i]只是依赖于dp[i - 1]的状态,所以只需要记录当前天和前一天的dp状态就可以了,可以简化为滚动数组
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
vector<vector<int>> dp(2, vector<int>(2)); // 注意这里只开辟了一个2 * 2大小的二维数组
dp[0][0] -= prices[0];
dp[0][1] = 0;
for (int i = 1; i < len; i++) {
dp[i % 2][0] = max(dp[(i - 1) % 2][0], -prices[i]);
dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]);
}
return dp[(len - 1) % 2][1];
}
};
时间复杂度:O(n)
空间复杂度:O(1)
leetcode 122. 买卖股票的最佳时机II
题目链接:买卖股票的最佳时机||
本题与上一题的区别是股票可以买卖多次。
递推公式如下:
(1)第i天持有股票,dp[i][0]可以由两个状态推出:
- 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 dp[i - 1][0]
- 第i天买入股票,所得现金就是买入今天的股票后所得现金dp[i - 1][1] - prices[i] - prices[i](与上一题唯一的区别)
则dp[i][0] = max(dp[i - 1][0],dp[i - 1][1] - prices[i] - prices[i])
(2)第i天不持有股票,dp[i][1]由两个状态推出来:
- 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 dp[i - 1][1]
- 第i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金 prices[i] + dp[i - 1][0]
则dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
版本一:
class Solution {
public:
int maxProfit(vector<int>& prices) {
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][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); //注意与上一题的区别
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
}
return dp[len - 1][1];
}
};
时间复杂度:O(n)
空间复杂度:O(n)
版本二:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
vector<vector<int>> dp(2, vector<int>(2)); // 注意这里只开辟了一个2 * 2大小的二维数组
dp[0][0] -= prices[0];
dp[0][1] = 0;
for (int i = 1; i < len; i++) {
dp[i % 2][0] = max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] - prices[i]);
dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]);
}
return dp[(len - 1) % 2][1];
}
};
时间复杂度:O(n)
空间复杂度:O(1)