持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
LeetCode 75 —— 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。
提示:
1 <= prices.length <= 105 0 <= prices[i] <= 104
来源:力扣(LeetCode) 链接:leetcode.cn/problems/be… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、思路分析:
-
这道题考察了什么思想?你的思路是什么?
这道题我看到的第一想法是暴力解法:
对数组中的每一个元素,比较其后面元素与之的利润差,取利润最大值即可。
但是这种方法并不妥当,经过深思熟虑,我想到了一个时间复杂度为O(n)的方法:
设置一个变量,存储遍历数组时,遇到的最低点,同时使用一个变量存储最大利润,每次将当前值与最低点进行求利润,然后与最大利润比较,这样貌似是可行的,我们来试一下吧!
-
做题的时候是不是一次通过的,遇到了什么问题,需要注意什么细节?
不是一次通过的,下面这种解法存在问题:
func maxProfit(prices []int) int { var low int = math.MaxInt64 var maxProfit int = 0 for num := range prices { if low > num { low = num } fmt.Println(low,num) if maxProfit < (num - low) { maxProfit = num - low } fmt.Println(maxProfit) } return maxProfit }当测试数据为[7,6,4,3,1]时,它会输出4,与预期结果0不符:
0 0 0 0 1 1 0 2 2 0 3 3 0 4 4这是什么问题呢?
经过排查,我发现
num := range prices时获取的全是数组索引,所以我们将该语句改为:_,num := range prices即可。 -
有几种解法,哪种解法时间复杂度最低,哪种解法空间复杂度最低,最优解法是什么?其他人的题解是什么,谁的效率更好一些?用不同语言实现的话,哪个语言速度最快?
class Solution {
public:
int maxProfit(vector<int>& prices) {
int ans = 0;
vector<int> St;
prices.emplace_back(-1); \ 哨兵👨•✈️
for (int i = 0; i < prices.size(); ++ i){
while (!St.empty() && St.back() > prices[i]){ \ 维护单调栈📈
ans = std::max(ans, St.back() - St.front()); \ 维护最大值
St.pop_back();
}
St.emplace_back(prices[i]);
}
return ans;
}
};
作者:wen-mu-yang
链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/solution/c-li-yong-shao-bing-wei-hu-yi-ge-dan-diao-zhan-tu-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
三、AC 代码:
func maxProfit(prices []int) int {
var low int = math.MaxInt64
var maxProfit int = 0
for _,num := range prices {
if low > num {
low = num
}
fmt.Println(low,num)
if maxProfit < (num - low) {
maxProfit = num - low
}
fmt.Println(maxProfit)
}
return maxProfit
}
四、总结:
暴力法的时间复杂度为O(n^2),空间复杂度为O(1),一次遍历法的时间复杂度为O(n),而其空间复杂度也为O(1)。
这说明有时候如果光掌握暴力解法是不行的,在数据量很大的情况下,可能会导致代码运行时间很长。
文慕阳大佬提出的使用利用哨兵👨✈️,维护一个单调栈,用 O(n) 的时间得知所有位置两边第一个比他大(或小)的数的位置。值得一学!
模板来源:
作者:掘金酱
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。