单调栈之Next Greater Number
單調棧之Next Greater Number
棧(stack) 是很簡單的?種數據結構, 先進后出的邏輯順序, 符合某些問
題的特點, ?如說函數調?棧。
單調棧實際上就是棧, 只是利?了?些巧妙的邏輯, 使得每次新元素?棧
后, 棧內的元素都保持有序(單調遞增或單調遞減) 。
聽起來有點像堆(heap) ? 不是的, 單調棧?途不太?泛, 只處理?種典型
的問題, 叫做 Next Greater Element。
?先, 講解 Next Greater Number 的原始問題: 給你?個數組, 返回?個等
?的數組, 對應索引存儲著下?個更?元素, 如果沒有更?的元素, 就存-1。 不好?語?解釋清楚, 直接上?個例?:
這道題的暴?解法很好想到, 就是對每個元素后?都進?掃描, 找到第?個
更?的元素就?了。 但是暴?解法的時間復雜度是 O(n2)O(n^2)O(n2)。
這個問題可以這樣抽象思考: 把數組的元素想象成并列站?的?, 元素??想象成?的??。 這些??對你站成?列, 如何求元素「2」 的 Next Greater Number 呢? 很簡單, 如果能夠看到元素「2」 , 那么他后?可?的第?個?就是「2」 的 Next Greater Number, 因為?「2」 ?的元素??不夠, 都被「2」 擋住了, 第?個露出來的就是答案。
這個情景很好理解吧? 帶著這個抽象的情景, 先來看下代碼。
vector<int> nextGreaterElement(vector<int>& nums) {vector<int> ans(nums.size()); // 存放答案的數組stack<int> s;for (int i = nums.size() - 1; i >= 0; i--) { // 倒著往棧?放while (!s.empty() && s.top() <= nums[i]) { // 判定個??矮s.pop(); // 矮個起開, 反正也被擋著了。 。 。} ans[i] = s.empty() ? -1 : s.top(); // 這個元素?后的第?個?個s.push(nums[i]); // 進隊, 接受之后的??判定吧!} return ans; }這就是單調隊列解決問題的模板。 for 循環要從后往前掃描元素, 因為我們借助的是棧的結構, 倒著?棧, 其實是正著出棧。 while 循環是把兩個“?個”元素之間的元素排除, 因為他們的存在沒有意義, 前?擋著個“更?”的元素, 所以他們不可能被作為后續進來的元素的 Next Great Number 了.
這個算法的時間復雜度不是那么直觀, 如果你看到 for 循環嵌套 while 循環, 可能認為這個算法的復雜度也是 O(n2)O(n^2)O(n2), 但是實際上這個算法的復雜度只有 O(n)O(n)O(n)
分析它的時間復雜度, 要從整體來看: 總共有 n 個元素, 每個元素都被push ?棧了?次, ?最多會被 pop ?次, 沒有任何冗余操作。 所以總的計算規模是和元素規模 n 成正?的, 也就是 O(n)O(n)O(n) 的復雜度
你已經掌握了單調棧的使?技巧, 來?個簡單的變形來加深?下理解:
給你?個數組 T = [73, 74, 75, 71, 69, 72, 76, 73], 這個數組存放的是近?天的天??溫(這?溫是鐵板燒? 不是的, 這??的華?度) 。 你返回?個數組, 計算: 對于每?天, 你還要?少等多少天才能等到?個更暖和的?溫;如果等不到那?天, 填 0 。
舉例: 給你 T = [73, 74, 75, 71, 69, 72, 76, 73], 你返回 [1, 1, 4, 2, 1, 1, 0, 0]。 解釋: 第?天 73 華?度, 第?天 74 華?度, ? 73 ?, 所以對于第?天, 只要等?天就能等到?個更暖和的?溫。 后?的同理相同類型的問題, 相同的思路, 直接調?單調棧的算法模板, 稍作改動就可以啦, 直接上代碼吧
vector<int> dailyTemperatures(vector<int>& T) {vector<int> ans(T.size());stack<int> s; // 這?放元素索引, ?不是元素for (int i = T.size() - 1; i >= 0; i--) {while (!s.empty() && T[s.top()] <= T[i]) {s.pop();} ans[i] = s.empty() ? 0 : (s.top() - i); // 得到索引間距s.push(i); // 加?索引, ?不是元素} return ans; }同樣是 Next Greater Number, 現在假設給你的數組是個環形的, 如何處理?
給你?個數組 [2,1,2,4,3], 你返回數組 [4,2,4,-1,4]。 擁有了環形屬性, 最后 ?個元素 3 繞了?圈后找到了????的元素 4 。Next Greater Number 的問題, 增加了環形屬性后, 問題的難點在于:這個 Next 的意義不僅僅是當前元素的右邊了, 有可能出現在當前元素的左邊.
我們可以考慮這樣的思路: 將原始數組“翻倍”, 就是在后?再接?個原始數組, 這樣的話, 按照之前“???”的流程, 每個元素不僅可以?較??右邊的元素, ?且也可以和左邊的元素?較了。
怎么實現呢? 你當然可以把這個雙倍?度的數組構造出來, 然后套?算法模板。 但是, 我們可以不?構造新數組, ?是利?循環數組的技巧來模擬。 直接看代碼吧:
vector<int> nextGreaterElements(vector<int>& nums) {int n = nums.size();vector<int> res(n); // 存放結果stack<int> s;// 假裝這個數組?度翻倍了for (int i = 2 * n - 1; i >= 0; i--) {while (!s.empty() && s.top() <= nums[i % n])s.pop();res[i % n] = s.empty() ? -1 : s.top();s.push(nums[i % n]);} return res; }總結
以上是生活随笔為你收集整理的单调栈之Next Greater Number的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LeetCode中二叉树相关题
- 下一篇: 单调队列之滑动窗口