[LeetCode] 901. Online Stock Span 股票價格跨度


Write a class StockSpanner which collects daily price quotes for some stock, and returns the span of that stock's price for the current day.html

The span of the stock's price today is defined as the maximum number of consecutive days (starting from today and going backwards) for which the price of the stock was less than or equal to today's price.git

For example, if the price of a stock over the next 7 days were [100, 80, 60, 70, 60, 75, 85], then the stock spans would be [1, 1, 1, 2, 1, 4, 6].github

Example 1:數組

Input: ["StockSpanner","next","next","next","next","next","next","next"], [[],[100],[80],[60],[70],[60],[75],[85]]
Output: [null,1,1,1,2,1,4,6]
Explanation:
First, S = StockSpanner() is initialized.  Then:
S.next(100) is called and returns 1,
S.next(80) is called and returns 1,
S.next(60) is called and returns 1,
S.next(70) is called and returns 2,
S.next(60) is called and returns 1,
S.next(75) is called and returns 4,
S.next(85) is called and returns 6.

Note that (for example) S.next(75) returned 4, because the last 4 prices
(including today's price of 75) were less than or equal to today's price.less

Note:函數

  1. Calls to StockSpanner.next(int price)will have 1 <= price <= 10^5.
  2. There will be at most 10000 calls to StockSpanner.next per test case.
  3. There will be at most 150000 calls to StockSpanner.next across all test cases.
  4. The total time limit for this problem has been reduced by 75% for C++, and 50% for all other languages.



這道題定義了一個 StockSpanner 的類,有一個 next 函數,每次給當天的股價,讓咱們返回以前連續多少天都是小於等於當前股價。跟 OJ 抗爭多年的經驗告訴咱們,不要想着能夠用最暴力的向前搜索的方法,這種解法太 trivial 了,確定沒法經過的。那麼能夠找連續遞增的子數組的長度麼,其實也是不行的,就拿題目中的例子來講吧 [100, 80, 60, 70, 60, 75, 85],數字 75 前面有三天是比它小的,可是這三天不是有序的,是先增後減的,那怎麼辦呢?咱們先從簡單的狀況分析,假如當前的股價要小於前一天的,那麼連續性直接被打破了,因此此時直接返回1就好了。可是假如大於等於前一天股價的話,狀況就比較 tricky 了,由於此時全部小於等於前一天股價的天數確定也是小於等於當前的,那麼咱們就須要知道是哪一天的股價恰好大於前一天的股價,而後用這一天的股價跟當前的股價進行比較,若大於當前股價,說明當前的連續天數就是前一天的連續天數加1,而若小於當前股價,咱們又要重複這個過程,去比較恰好大於以前那個的股價。因此咱們須要知道對於每一天,往前推恰好大於當前股價的是哪一天,用一個數組 pre,其中 pre[i] 表示從第i天往前推恰好大於第i天的股價的是第 pre[i] 天。接下來看如何實現 next 函數,首先將當前股價加入 nums 數組,而後前一天在數組中的位置就是 (int)nums.size()-2。再來想一想 corner case 的狀況,假如當前是數組中的第0天,前面沒有任何股價了,咱們的 pre[0] 就賦值爲 -1 就好了,怎麼知道當前是不是第0天,就看 pre 數組是否爲空。再有就是因爲i要不斷去 pre 數組中找到以前的天數,因此最終i是有可能到達 pre[0] 的,那麼就要判斷當i爲 -1 時,也要中止循環。循環的最後一個條件就是當以前的股價小於等當前的估計 price 時,才進行循環,這個前面講過了,循環內部就是將 pre[i] 賦值給i,這樣就完成了跳到以前天的操做。while 循環結束後要將i加入到 pre 數組,由於這個i就是從當前天往前推,一個大於當前股價的那一天,有了這個i,就能夠計算出連續天數了,參見代碼以下:this



解法一:spa

class StockSpanner {
public:
    StockSpanner() {}
    
    int next(int price) {
        nums.push_back(price);
        int i = (int)nums.size() - 2;
        while (!pre.empty() && i >= 0 && nums[i] <= price) {
            i = pre[i];
        }
        pre.push_back(i);
        return (int)pre.size() - 1 - i;
    }

private:
    vector<int> nums, pre;
};



咱們還可使用棧來作,裏面放一個 pair 對兒,分別是當前的股價和以前比其小的連續天數。在 next 函數中,使用一個 cnt 變量,初始化爲1。仍是要個 while 循環,其實核心的本質都是同樣的,循環的條件首先是棧不能爲空,而且棧頂元素的股價小於等於當前股價,那麼 cnt 就加上棧頂元素的連續天數,能夠感覺到跟上面解法在這裏的些許不一樣之處了吧,以前是一直找到第一個大於當前股價的天數在數組中的位置,而後相減獲得連續天數,這裏是在找的過程當中直接累加連續天數,最終均可以獲得正確的結果,參見代碼以下:code



解法二:htm

class StockSpanner {
public:
    StockSpanner() {}
    
    int next(int price) {       
        int cnt = 1;
        while (!st.empty() && st.top().first <= price) {
            cnt += st.top().second; st.pop();
        }
        st.push({price, cnt});
        return cnt;
    }

private:
    stack<pair<int, int>> st;
};



Github 同步地址:

https://github.com/grandyang/leetcode/issues/901



參考資料:

https://leetcode.com/problems/online-stock-span/

https://leetcode.com/problems/online-stock-span/discuss/168311/C%2B%2BJavaPython-O(1)

https://leetcode.com/problems/online-stock-span/discuss/168288/Java-short-solution-using-list-with-explanation



LeetCode All in One 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索