桟、队列相关

stack:

 

 

 

 

括号匹配 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

 

 

 232. Implement Queue using Stacks(队列实现栈)  

 155. 最小栈 (辅助栈)

 

 

queue:

 

 

 

 

 

 

 deque

 

 

  

单调栈:

 

栈(stack)是很简单的一种数据结构,先进后出的逻辑顺序,符合某些问题的特点,比如说函数调用栈。

单调栈实际上就是栈,只是利用了一些巧妙的逻辑,使得每次新元素入栈后,栈内的元素都保持有序(单调递增或单调递减)。

 https://leetcode-cn.com/problems/remove-duplicate-letters/solution/yi-zhao-chi-bian-li-kou-si-dao-ti-ma-ma-zai-ye-b-4/

以下列出了单调栈的问题,供大家参考。

序号 题目 题解


5 901. 股票价格跨度(中等) 「力扣」第 901 题:股票价格跨度(单调栈)

 

听起来有点像堆(heap)?不是的,单调栈用途不太广泛,只处理一种典型的问题,叫做 Next Greater Element。本文用讲解单调队列的算法模版解决这类问题,并且探讨处理「循环数组」的策略。

 
 
 
 

 496. Next Greater Element I (单调栈)

 

单调栈模板

首先,看一下 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;
}

  

循环数组(最后一个元素的下一个元素是数组的第一个元素)的下一个更大元素。

同样是 Next Greater Number,现在假设给你的数组是个环形的,如何处理?力扣第 503 题「下一个更大元素 II」就是这个问题:

比如输入一个数组 [2,1,2,4,3],你返回数组 [4,2,4,-1,4]。拥有了环形属性,最后一个元素 3 绕了一圈后找到了比自己大的元素 4

一般是通过 % 运算符求模(余数),来获得环形特效:

 
int[] arr = {1,2,3,4,5};
int n = arr.length, index = 0;
while (true) {
print(arr[index % n]);
index++;
}

这个问题肯定还是要用单调栈的解题模板,但难点在于,比如输入是 [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 };

 

739. 每日温度

 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 };

 

 

 

1.视野总和
描叙:有n个人站队,所有的人全部向右看,个子高的可以看到个子低的发型,给出每个人的身高,问所有人能看到其他人发现总和是多少。
输入:4 3 7 1
输出:2
解释:个子为4的可以看到个子为3的发型,个子为7可以看到个子为1的身高,所以1+1=2

 

class Solution {
public:
    int sight_sum(vector<int>& heights) {
        stack<int> stk;
        int sum = 0;
        for(int i =0;i < heights.size();i++) {
            while(!stk.empty() && heights[stk.top()] < heights[i]) {
                int top = stk.top();
                stk.pop();
                sum += (i-top-1);
            }
            stk.push(i);
        }
        return sum;
    }
};

 

  84. 柱状图中最大的矩形 (双指针、单调栈)

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        stack<int> stk;
        int res = 0;
        int top = 0;
        heights.push_back(-1);
        stk.push(-1);
        for(int i =0;i < heights.size();i++) {
            while(stk.top()!=-1 && heights[stk.top()] > heights[i]) {
                top = stk.top();
                stk.pop();
                res = max(res, heights[top] *(i-stk.top()-1));
            }
            stk.push(i);
        }
        return res;
    }
};

 

 

316. 去除重复字母(单调栈) 

 

class Solution:
    def removeDuplicateLetters(self, s: str) -> str:
        s_map = {}
        for i in s:
            if i in s_map:
                s_map[i]+=1
            else:
                s_map[i] =1

        stk = []
        for ch in s:
            if ch not in stk:
                while stk and s_map[stk[-1]]>0 and ch < stk[-1]:
                    stk.pop()
                stk.append(ch)
            s_map[ch]-=1
        return "".join(stk)

 

  

402. 移掉 K 位数字(单调栈)

单调递增栈,栈顶保存最大元素。

class Solution:
    def removeKdigits(self, num: str, k: int) -> str:
        stk = []
        nk = len(num)-k
        for ch in num:
            while k and stk and ch < stk[-1]:
                stk.pop()
                k-=1
            stk.append(ch)
        res = ''.join(stk[:nk]).lstrip('0')
        if res == "":
            res = "0"
        return res

  

321. 拼接最大数(单调栈)

 
class Solution:
    def maxNumber(self, nums1, nums2, k):

        def pick_max(nums, k):
            stack = []
            drop = len(nums) - k
            for num in nums:
                while drop and stack and stack[-1] < num:
                    stack.pop()
                    drop -= 1
                stack.append(num)
            return stack[:k]

        def merge(A, B):
            ans = []
            while A and B:
                if  A > B:
                    ans.append(A.pop(0))
                else:
                    ans.append(B.pop(0))
            while A:
                ans.append(A.pop(0))
            while B:
                ans.append(B.pop(0))
            return ans

        max_res = []
        for  i in range(k+1):
            if i <= len(nums1) and k-i <= len(nums2):
                max_res = max(max_res, merge(pick_max(nums1, i), pick_max(nums2, k-i)))
        return max_res

 

456. 132 模式(单调栈)

 单调递减栈,栈顶保存最小值

class Solution {
public:
    bool find132pattern(vector<int>& nums) {
        stack<int> stk;
        int top = INT_MIN;
        //// s1 s3 s2
        //keep the value of s3 as big as possible
        //use a "sorted" stack to maintain the candidates of s2 and s3.
        for(int i =nums.size()-1; i >=0;i--) {
            if (top>nums[i]) return true;            
            while(!stk.empty() && nums[i] > stk.top()) {
                top = stk.top();
                stk.pop();
            }   
            stk.push(nums[i]);            
        }
        return false;
    }
};

 

 

581. 最短无序连续子数组(单调栈) 

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        int start = INT_MAX;
        int end = INT_MIN;
        stack<int> stk;
        stack<int> stk2;
        for(int i = 0; i < nums.size(); i++) {
            while(!stk.empty() && nums[i]< nums[stk.top()]) {
                start = min(stk.top(),start);
                stk.pop();
            }
            stk.push(i);
        }
        for(int i = nums.size() - 1; i >=0 ; i--) {
            while(!stk2.empty() && nums[i] > nums[stk2.top()]) {
                end = max(stk2.top(),end);
                stk2.pop();
            }
            stk2.push(i);
        }
        if (start ==INT_MAX  &&  end == INT_MIN) return 0;
        return end - start +1;
    }
};

 

  

单调队列: 

 

 239. Sliding Window Maximum (滑动窗口最大值, 大根堆or 单调队列)

 

posted @ 2018-02-24 15:00  乐乐章  阅读(128)  评论(0编辑  收藏  举报