1.題目
題目地址(901. 股票價格跨度 - 力扣(LeetCode))
https://leetcode.cn/problems/online-stock-span/
題目描述
設計一個演算法收集某些股票的每日報價,並返回該股票當日價格的 跨度 。
當日股票價格的 跨度 被定義為股票價格小於或等於今天價格的最大連續日數(從今天開始往回數,包括今天)。
-
例如,如果未來 7 天股票的價格是
[100,80,60,70,60,75,85]
,那麼股票跨度將是[1,1,1,2,1,4,6]
。
實現 StockSpanner
類:
StockSpanner()
初始化類物件。int next(int price)
給出今天的股價price
,返回該股票當日價格的 跨度 。
示例:
輸入: ["StockSpanner", "next", "next", "next", "next", "next", "next", "next"] [[], [100], [80], [60], [70], [60], [75], [85]] 輸出: [null, 1, 1, 1, 2, 1, 4, 6] 解釋: StockSpanner stockSpanner = new StockSpanner(); stockSpanner.next(100); // 返回 1 stockSpanner.next(80); // 返回 1 stockSpanner.next(60); // 返回 1 stockSpanner.next(70); // 返回 2 stockSpanner.next(60); // 返回 1 stockSpanner.next(75); // 返回 4 ,因為截至今天的最後 4 個股價 (包括今天的股價 75) 都小於或等於今天的股價。 stockSpanner.next(85); // 返回 6
提示:
1 <= price <= 105
- 最多呼叫
next
方法104
次
2.題解
2.1單調棧
思路
這裡尋找股票價格小於或等於今天價格的最大連續日數, 反過來說,不成立條件就是尋找左側最近的更大值(大於當前日股票價格,連續日數就中斷了)
這裡尋找左側更大值,也就是尋找prices[stk.top()] > price
, 所以反過來我們這裡while執行的條件就是prices[stk.top()] <= price
我們使用了一個陣列來儲存之前的股票值,並且透過陣列大小判斷當前位置索引
1.如果棧空,說明當前股價是目前遇到的最大值,這時候其實第一個不滿足條件的索引值可以看做是-1, 所以距離就是i-(-1)=i+1
2.如果棧不為空,而是遇到了某個更大的值停了下來,獲得它的索引, 距離是i-index(為何不加一?因為這是第一個不滿足的值,而不是最後一個滿足的值)
但是這裡我們額外用了一個陣列,可以思考一下如何去除這個陣列的使用
程式碼
- 語言支援:C++
C++ Code:
class StockSpanner {
public:
StockSpanner() {}
int next(int price) {
while(!stk.empty() && price >= prices[stk.top()]){
stk.pop();
}
prices.push_back(price);
int i = prices.size() - 1;
int ans = stk.empty()?(i + 1) : i - stk.top();
stk.push(i);
return ans;
}
private:
vector<int> prices;
stack<int> stk;
};
/**
* Your StockSpanner object will be instantiated and called as such:
* StockSpanner* obj = new StockSpanner();
* int param_1 = obj->next(price);
*/
複雜度分析
令 n 為陣列長度。
- 時間複雜度:\(O(n)\)
- 空間複雜度:\(O(n)\)
2.2 單調棧(改進,不使用陣列記錄)
思路
如果不使用陣列記錄,我們要解決兩個使用prices陣列的替換
1.prices[stk.top()]
,我們之前棧中儲存的是索引值,我們如何透過索引值獲取相應值的大小?
2.int i = prices.size() - 1;
這裡我們獲取當前元素的索引值用的是陣列大小來求的,如果不使用,該如何獲取?
解決:
1.我們的棧不僅記錄索引值,也記錄相應值(stack中儲存一個pair元素即可)
2.我們使用一個成員變數idx記錄當前元素的索引值,每次操作的時候idx++即可
備註:這裡還進行了一個小最佳化,本來我們要判斷棧是否為空,這裡預先往棧中新增了一個(-1,INT_MAX)保證棧不為空
程式碼
class StockSpanner {
public:
StockSpanner() {
this->idx = -1;
this->stk.emplace(-1,INT_MAX);
}
int next(int price) {
while(!stk.empty() && stk.top().second <= price){
stk.pop();
}
idx++;
int ans = idx - stk.top().first;
stk.emplace(idx, price);
return ans;
}
private:
stack<pair<int,int>> stk;
int idx;
};
/**
* Your StockSpanner object will be instantiated and called as such:
* StockSpanner* obj = new StockSpanner();
* int param_1 = obj->next(price);
*/