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:函数
StockSpanner.next(int price)
will have 1 <= price <= 10^5
.10000
calls to StockSpanner.next
per test case.150000
calls to StockSpanner.next
across all test cases.
这道题定义了一个 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)