买卖股票的最佳时机 |
题目描述
题目链接:121. 买卖股票的最佳时机
给定一个数组 prices
,它的第 i
个元素 prices[i]
表示一支给定股票第 i
天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0
。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
解法一:暴力解法
暴力法就很简单咯,直接两层循环,即假设每一天的股票都买一遍,并且买到时,将后面的天数卖出的情况都进行计算利润。
class Solution {
public int maxProfit(int[] prices) {
int result = 0;
for(int i = 0; i < prices.length; i++) {
for(int j = i + 1; j < prices.length; j++) {
if(result < prices[j]-prices[i]) result = prices[j]-prices[i];
}
}
return result;
}
}
复杂度如下:
时间复杂度:O(n^2)
空间复杂度:O(1)
当然这个方法超时了,在力扣上并无法通过。
解法二:贪心法
贪心法的关键思想:找到左边最小且(右边的利润)最大咯。
那么在循环从左到右遍历时,应找最小值,并更新最大利润。
代码如下:
class Solution {
public int maxProfit(int[] prices) {
// 老操作使初始化min_prices最大,而max_prices为0
int min_prices = Integer.MAX_VALUE;
int max_prices = 0;
// 从左到右遍历
for(int i = 0; i < prices.length; i++) {
// 更新查找最小值
min_prices = Math.min(min_prices, prices[i]);
// 比较最大利润
max_prices = Math.max(max_prices, prices[i]-min_prices);
}
// 返回最大利润
return max_prices;
}
}
贪心法的复杂度
时间复杂度:O(n)
空间复杂度:O(1)
解法三:动态规划法
-
确定dp数组的含义
dp[i][0]
表示第i天持有股票所拥有的最多现金,一开始所拥有现金为0,第i天买入股票时,现金则是
-prices[i],是一个负数。
而
dp[i][1]
则表示第i天不拥有股票时的最多现金。 -
确定递推公式
-
若第i-1天就持有股票,那么
dp[i][0] = dp[i-1][0]
保持原状。 -
若第i天买入股票,那么
dp[i][0] = -prices[i]
那么
dp[i][0]
应该选最大的,即dp[i][0] = Math.max(dp[i-1][0], -prices[i])
- 若第i-1天不持有股票,那么
dp[i][1] = dp[i-1][1]
- 若第i-1天持有股票,第i天卖出股票,那么
dp[i][1] = dp[i-1][0]+prices[i]
那么
dp[i][1]
应该选最大的,即dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]+prices[i])
-
-
dp数组的初始化
从递推公式我们可以得到,dp数组的值都需要从
dp[0][0]
和dp[0][1]
得到的,因此我们需要初始化这两个值。dp[0][0]
意味着第0天持有股票,也就是说第0天就买入股票,则dp[0][0] = -prices[0]
dp[0][1]
意味着第0天未持有股票,就是说那天没有买入股票,则dp[0][1] = 0
-
确定遍历顺序
从递推公式可以看出
dp[i]
都是由dp[i-1]
推导出来的,则说明一定是从前往后遍历。
写出代码如下:
class Solution {
public int maxProfit(int[] prices) {
int leng = prices.length;
// 创建dp数组
// dp[i][0]代表第i天持有股票的最大收益
// dp[i][1]代表第i天不持有股票的最大收益
int[][] dp = new int[leng][2];
// 初始化dp数组
dp[0][0] = -prices[0];
dp[0][1] = 0;
// 从前往后遍历,且i从1开始
for(int i = 1; i < leng; i++) {
dp[i][0] = Math.max(dp[i-1][0], -prices[i]);
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]+prices[i]);
}
return dp[leng-1][1];
}
}
复杂度:
时间复杂度:O(n)
空间复杂度:O(n^2)