力扣-901. 股票價格跨度

DawnTraveler發表於2024-05-17

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);
 */

相關文章