JHHK

欢迎来到我的个人网站
行者常至 为者常成

【题目】3、栈与队列

目录

基本概念


先进后出,后进先出
对称

队列、双端队列
先进先出,后进后出
顺序

155.最小栈

题目描述


155. 最小栈      

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。      

push(x) —— 将元素 x 推入栈中。      
pop() —— 删除栈顶的元素。      
top() —— 获取栈顶元素。      
getMin() —— 检索栈中的最小元素。      
  

示例:      
输入:      
["MinStack","push","push","push","getMin","pop","top","getMin"]      
[[],[-2],[0],[-3],[],[],[],[]]      

输出:      
[null,null,null,null,-3,null,0,-2]      

解释:      
MinStack minStack = new MinStack();      
minStack.push(-2);      
minStack.push(0);      
minStack.push(-3);      
minStack.getMin();   --> 返回 -3.      
minStack.pop();      
minStack.top();      --> 返回 0.      
minStack.getMin();   --> 返回 -2.      
  

提示:      
pop、top 和 getMin 操作总是在 非空栈 上调用。   

题目实现

class MinStack {
    stack<int> stackA;
    stack<int> stackB;
public:
    /** initialize your data structure here. */
    MinStack() {
        
    }
    
    void push(int x) {
        stackA.push(x);
        if (stackB.size() == 0) {
            stackB.push(x);
        }else{
            int top =  stackB.top();
            top < x ? stackB.push(top) : stackB.push(x);
        }
    }
    
    void pop() {
        if (stackA.size() == 0)return;
        stackA.pop();
        stackB.pop();
    }
    
    int top() {
        return stackA.top();
    }
    
    int getMin() {
        return stackB.top();
    }
};

20.有效的括号

题目描述

_20_有效的括号 -https://leetcode-cn.com/problems/valid-parentheses/

给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。      

有效字符串需满足:      

左括号必须用相同类型的右括号闭合。      
左括号必须以正确的顺序闭合。      
注意空字符串可被认为是有效字符串。      

示例 1:      

输入: "()"      
输出: true      
示例 2:      

输入: "()[]{}"      
输出: true      
示例 3:      

输入: "(]"      
输出: false      
示例 4:      

输入: "([)]"      
输出: false      
示例 5:      

输入: "{[]}"      
输出: true      

题目实现

class Solution {
public:
    bool isValid(string s) {
        int n = (int)s.size();
        if (n & 1 == 1) return false;
        
        unordered_map<char, char> pairs = {
            {')', '('},
            {']', '['},
            {'}', '{'}
        };
        
        stack<char> stk;
        
        for (char ch: s) {
            //pairs.count,判断key是否存在,存在返回1,不存在返回0
            if (pairs.count(ch)) {//如果是右半边出栈
                //右半边时,栈为空或栈顶不能配对,不可能是有效的括号
                if (stk.empty() || stk.top() != pairs[ch]) return false;
                
                stk.pop();
            }else {//如果是左半边入栈
                stk.push(ch);
            }
        }
        return stk.empty();
    }
};

232.用栈实现队列

题目描述

232. 用栈实现队列- https://leetcode-cn.com/problems/implement-queue-using-stacks/       
 
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列的支持的所有操作(push、pop、peek、empty):       

实现 MyQueue 类:       
void push(int x) 将元素 x 推到队列的末尾       
int pop() 从队列的开头移除并返回元素       
int peek() 返回队列开头的元素       
boolean empty() 如果队列为空,返回 true ;否则,返回 false       
  

说明:       
你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。       
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。       
  

进阶:       
你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。       
  

示例:       

输入:       
["MyQueue", "push", "push", "peek", "pop", "empty"]       
[[], [1], [2], [], [], []]       
输出:       
[null, null, null, 1, 1, false]       

解释:       
MyQueue myQueue = new MyQueue();       
myQueue.push(1); // queue is: [1]       
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)       
myQueue.peek(); // return 1       
myQueue.pop(); // return 1, queue is [2]       
myQueue.empty(); // return false       
  

提示:       
1 <= x <= 9       
最多调用 100 次 push、pop、peek 和 empty       
假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)       

题目实现

class MyQueue {
    stack<int> * inStack;
    stack<int> * outStack;
public:
    /** Initialize your data structure here. */
    MyQueue() {
        this->inStack = new stack<int>();
        this->outStack = new stack<int>();
    }
    
    ~MyQueue(){
        delete inStack;
        inStack = nullptr;
        
        delete outStack;
        outStack = nullptr;
    }
    
    
    /** Push element x to the back of queue. */
    void push(int x) {
        this->inStack->push(x);
    }
    
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {

        if (outStack->size() == 0) {
            while (inStack->size()!=0) {
                outStack->push(inStack->top());
                inStack->pop();
            }
        }
        
        int val = this->outStack->top();
        this->outStack->pop();
        return val;
    }
    
    /** Get the front element. */
    int peek() {
        if (outStack->size() == 0) {
            while (inStack->size()!=0) {
                outStack->push(inStack->top());
                inStack->pop();
            }
        }

        return outStack->top();
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return outStack->size() == 0 && inStack->size() == 0;
    }
};

239.滑动窗口最大值

题目描述

239. 滑动窗口最大值

 给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。
 你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

 返回滑动窗口中的最大值。

 进阶:
 你能在线性时间复杂度内解决此题吗?

 示例:

 输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
 输出: [3,3,5,5,6,7]
 解释:

   滑动窗口的位置                最大值
 ---------------               -----
 [1  3  -1] -3  5  3  6  7       3
  1 [3  -1  -3] 5  3  6  7       3
  1  3 [-1  -3  5] 3  6  7       5
  1  3  -1 [-3  5  3] 6  7       5
  1  3  -1  -3 [5  3  6] 7       6
  1  3  -1  -3  5 [3  6  7]      7
  

 提示:

 1 <= nums.length <= 10^5
 -10^4 <= nums[i] <= 10^4
 1 <= k <= nums.length

实现方式一

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        
        //返回一个空数组
        if (nums.size() == 0 || k < 1) return vector<int>(0);
        
        //返回nums
        if (k == 1) return nums;
        
        //创建一个存放滑动窗口最大值的数组
        int length = (int)nums.size()-k+1;
        vector<int> maxes(length);//6 - 3 +1
        
        int maxIdx = -1;
        for (int i = 0; i<length; i++) {
            if (maxIdx<i) {
                maxIdx = maxIdxFromK(nums, i, i+k-1);
            }else{
                if(nums[i+k-1] > nums[maxIdx]){
                    maxIdx = i+k-1;
                }
            }
            maxes[i] = nums[maxIdx];
            
            cout<<maxIdx<<endl;
            
        }
        return maxes;
    }
    
    
    int maxIdxFromK(vector<int>& nums,int star,int end){
        int maxIdx = star;
        for (int i = star+1; i<=end; i++) {
            if (nums[i] > nums[maxIdx]) {
                maxIdx = i;
            }
        }
        return maxIdx;
    }
};

实现方式二:双端队列

//时间复杂度O(n),空间复杂度O(n-k)

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        //返回一个空数组
        if (nums.size() == 0 || k < 1) return vector<int>(0);
        
        //返回nums
        if (k == 1) return nums;
        
        //创建一个存放滑动窗口最大值的数组
        vector<int> maxes(nums.size()-k+1);

        //创建一个双端队列
        deque<int> intDeque;
        
        for (int ri = 0; ri<nums.size(); ri++) {
            
            // 只要nums[队尾] <= nums[i],就删除队尾
            while (!intDeque.empty() && nums[ri] >= nums[intDeque.back()]) {
                intDeque.pop_back();
            }
            
            // 将i加到队尾
            intDeque.push_back(ri);
            
            // 检查窗口的索引是否合法
            int li = ri - k + 1;
            if (li < 0) continue;
            
            // 检查队头的合法性
            if (intDeque.front() < li) {
                // 队头不合法(失效,不在滑动窗口索引范围内)
                intDeque.pop_front();
            }
            
            // 设置窗口的最大值
            maxes[li] = nums[intDeque.front()];
        }
        return maxes;
    }
};


行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.