stack:
queue:
deque
232. Implement Queue using Stacks(队列实现栈)
单调栈:
栈(stack)是很简单的一种数据结构,先进后出的逻辑顺序,符合某些问题的特点,比如说函数调用栈。
单调栈实际上就是栈,只是利用了一些巧妙的逻辑,使得每次新元素入栈后,栈内的元素都保持有序(单调递增或单调递减)。
听起来有点像堆(heap)?不是的,单调栈用途不太广泛,只处理一种典型的问题,叫做 Next Greater Element。本文用讲解单调队列的算法模版解决这类问题,并且探讨处理「循环数组」的策略。
首先,看一下 Next Greater Number 的原始问题,这是力扣第 496 题「下一个更大元素 I」:
给你一个数组,返回一个等长的数组,对应索引存储着下一个更大元素,如果没有更大的元素,就存 -1。
函数签名如下:
比如说,输入一个数组 nums = [2,1,2,4,3],你返回数组 [4,2,4,-1,-1]。
解释:第一个 2 后面比 2 大的数是 4; 1 后面比 1 大的数是 2;第二个 2 后面比 2 大的数是 4; 4 后面没有比 4 大的数,填 -1;3 后面没有比 3 大的数,填 -1。
这道题的暴力解法很好想到,就是对每个元素后面都进行扫描,找到第一个更大的元素就行了。但是暴力解法的时间复杂度是 O(n^2)。
这个问题可以这样抽象思考:把数组的元素想象成并列站立的人,元素大小想象成人的身高。这些人面对你站成一列,如何求元素「2」的 Next Greater Number 呢?很简单,如果能够看到元素「2」,那么他后面可见的第一个人就是「2」的 Next Greater Number,因为比「2」小的元素身高不够,都被「2」挡住了,第一个露出来的就是答案。
vector<int> nextGreaterElement(vector<int>& nums) { vector<int> res(nums.size()); // 存放答案的数组 stack<int> s; // 倒着往栈里放 for (int i = nums.size() - 1; i >= 0; i--) { // 判定个子高矮 while (!s.empty() && s.top() <= nums[i]) { // 矮个起开,反正也被挡着了。。。 s.pop(); } // nums[i] 身后的 next great number res[i] = s.empty() ? -1 : s.top(); // s.push(nums[i]); } return res; }
496. Next Greater Element I (单调栈)
1 class Solution { 2 public: 3 vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) { 4 stack<int> stk; 5 unordered_map<int,int> next_map; 6 for(int i = nums2.size()-1; i >=0 ;--i) { 7 while(!stk.empty() && stk.top() <= nums2[i]) { 8 stk.pop(); 9 } 10 next_map[nums2[i]] = stk.empty()?-1:stk.top(); 11 stk.push(nums2[i]); 12 13 } 14 vector<int> res; 15 for(auto i: nums1){ 16 res.emplace_back(next_map[i]); 17 } 18 return res; 19 } 20 };
循环数组(最后一个元素的下一个元素是数组的第一个元素)的下一个更大元素。
同样是 Next Greater Number,现在假设给你的数组是个环形的,如何处理?力扣第 503 题「下一个更大元素 II」就是这个问题:
比如输入一个数组 [2,1,2,4,3],你返回数组 [4,2,4,-1,4]。拥有了环形属性,最后一个元素 3 绕了一圈后找到了比自己大的元素 4。
一般是通过 % 运算符求模(余数),来获得环形特效:
这个问题肯定还是要用单调栈的解题模板,但难点在于,比如输入是 [2,1,2,4,3],对于最后一个元素 3,如何找到元素 4 作为 Next Greater Number。
对于这种需求,常用套路就是将数组长度翻倍:
1 class Solution { 2 public: 3 vector<int> nextGreaterElements(vector<int>& nums) { 4 stack<int> stk; 5 int n = nums.size(); 6 vector<int> res(n); 7 for(int i = n*2-1;i >=0; --i) { 8 while(!stk.empty()&& stk.top()<=nums[i%n]) { 9 stk.pop(); 10 } 11 res[i%n] = stk.empty()?-1:stk.top(); 12 stk.push(nums[i%n]); 13 } 14 return res; 15 } 16 };
1 class Solution { 2 public: 3 vector<int> dailyTemperatures(vector<int>& temperatures) { 4 stack<int> stk; 5 vector<int> res(temperatures.size()); 6 for(int i = temperatures.size() -1 ; i >= 0 ; --i) { 7 while(!stk.empty() && temperatures[stk.top()] <= temperatures[i]) { 8 stk.pop(); 9 } 10 res[i] = stk.empty()?0:stk.top() - i; 11 stk.push(i); 12 } 13 return res; 14 } 15 };
单调队列:
随笔标题: 239. Sliding Window Maximum (滑动窗口最大值, 大根堆or 单调队列)
BST的LCA(最低公共祖先) http://www.cnblogs.com/zle1992/p/7753161.html
BT的LCA(最低公共祖先) http://www.cnblogs.com/zle1992/p/8419511.html
括号匹配 20 :http://www.cnblogs.com/zle1992/p/8469603.html
最长括号匹配32 :http://www.cnblogs.com/zle1992/p/8469694.html
RPN逆波兰表达式 150 :http://www.cnblogs.com/zle1992/p/8469734.html