Leetcode解题系列(4)

Leetcode解题系列(4)

225 用队列实现栈

题目描述:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通队列的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/implement-stack-using-queues
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

示例2:
输入:
[“CQueue”,“deleteHead”,“appendTail”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]
简单来说,就是要将栈封装成一个队列,让其实现队列的逻辑功能;
栈和队列的区别就是:栈是先进后出,可以类比于现实生活中压子弹的过程,先压入的最后打出来;
而队列就像在食堂排队一样,先进去的先出来,后进去的后出来
队列和栈是两种常用的数据结构:
下面详细介绍这两种数据结构:
队列:先进先出,可以想象成在排队的一个队伍,不过加入元素和提出元素都是人为控制的

常用函数:

//queue队列常用函数
//在c++中#include<queue>就可以使用队列类了
queue<int> q1;//声明一个队列对象
q1.push(1);//在队列尾部插入一个元素
q1.pop();//将最靠前的元素弹出,void型函数,不返回
q1.size();//返回队列元素个数
q1.empty();//判断队列是否为空
q1.front();//返回最早进入队列的元素,但并不剔除
q1.back();//返回最后进入的元素,不做任何操作

栈:元素进出的顺序为先进后出,可以理解为压子弹夹,先压进去的子弹最后打出,后压进去的先打出来

常用函数:

#include<stack>
stack<int> s;
s.push(1);
s.pop();//不返回
s.top();//返回但不弹出
s.empty();

用两个队列实现栈
主要解决的问题是进出的顺序问题。
由于队列和栈的进出顺序不同,我们可以这样想,假设前n-1个队列中的元素的顺序是正确的,现又新push一个元素(第n个元素),这样,这个最后加入的元素需要在队列的最前端(最先进入队列的元素),所以我们可以使用两个队列,每次push要做的事情就是先将一个单独的元素push进一个空队列,然后将另一个队列中的所有元素依次pop出来再push进入这个队列,这样每个过程结束后都有一个空队列和一个有内容的队列,而队列中元素的顺序是和栈相同的,可以直接pop出来。

class MyStack {
public:
    /** Initialize your data structure here. */
    queue<int> q1,q2;
    MyStack() {

    }
    
    /** Push element x onto stack. */
    void push(int x) {
        if(q1.empty()){
            q1.push(x);
           while(!q2.empty()){
               q1.push(q2.front());
               q2.pop();
           }
        }else{
            q2.push(x);
           while(!q1.empty()){
               q2.push(q1.front());
               q1.pop();
           }
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int res=0;
        if(!q1.empty()){
            res=q1.front();
            q1.pop();
            return res;
        }
        if(!q2.empty()){
            res=q2.front();
            q2.pop();
            return res;
        }
        return res;
    }
    
    /** Get the top element. */
    int top() {
        if(!q1.empty())return q1.front();
        if(!q2.empty())return q2.front();
        return 0;
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        if((q1.empty())&&(q2.empty()))return true;
        return false;
    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */

代码实现是比较简单的。
主要需要注意的就是,C++中的栈和队列的函数还是有一些差别的,比如队列的pop()不会返回栈顶元素,所以要先用front()得到栈顶元素后再用pop()
接下来用一个队列实现:只要每次push以后,再将前面的元素依次pop出来再push进去,就可以实现栈的逻辑进出:
(有点像首尾循环的意思,自己可以画图看一下)

class MyStack {
public:
queue<int> q;
    /** Initialize your data structure here. */
    MyStack() {

    }
    
    /** Push element x onto stack. */
    void push(int x) {
        q.push(x);
        for(int i=0;i<q.size()-1;i++){
            q.push(q.front());
            q.pop();
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int i=q.front();
        q.pop();
        return i;
    }
    
    /** Get the top element. */
    int top() {
        return q.front();
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return q.empty();
    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */

20、有效的括号

题目描述: 给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
思路 这个匹配括号的过程很容易想到用栈的数据结构来实现
我想到的思路就是每种括号都维护一个栈,当遍历字符串时,每遇到一个左括号时就入栈,遇到右括号时就将左括号出栈,这样到了最后的时候,当三个栈都为空时就表示有效,输出true,若输入右括号时栈就已经空了或到字符串末尾时栈不为空,则表示括号无效,输出false;
代码如下:

class Solution {
public:
    bool isValid(string s) {
        stack<int> s1;
        char curr=s[0];int i=0;
        for(i=0;i<s.length();i++){
            
           if(curr=='('){
               s1.push(1);
           } 
           if(curr=='{'){
               s1.push(2);
           } 
           if(curr=='['){
               s1.push(3);
           } 
           if(curr==')'){
                if(s1.empty()){
            return false;
        }
               if(s1.top()==1){
                   s1.pop();
               }else return false;
           }
           if(curr=='}'){
               if(s1.empty()){
            return false;
        }
               if(s1.top()==2){
                   s1.pop();
               }else return false;
           }
           if(curr==']'){
               if(s1.empty()){
            return false;
        }
               if(s1.top()==3){
                   s1.pop();
               }else return false;
           }
           
           curr=s[i+1];
        }
        if(s1.empty()){
            return true;
        }else return false;
    }    
};

这个方法是可行的
也可以用下面的方法:

class Solution {
public:
    bool isValid(string s) {
        int n = s.size();
        if (n % 2 == 1) {
            return false;
        }

        unordered_map<char, char> pairs = {
            {')', '('},
            {']', '['},
            {'}', '{'}
        };
        stack<char> stk;
        for (char ch: s) {
            if (pairs.count(ch)) {
                if (stk.empty() || stk.top() != pairs[ch]) {
                    return false;
                }
                stk.pop();
            }
            else {
                stk.push(ch);
            }
        }
        return stk.empty();
    }
};

155、最小栈

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

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

要在常数时间内检索到最小元素,这就说明不能使用getMin()函数才去排序,否则肯定不会是常数时间;
需要在栈外再维护一个空间,记录大小顺序和在站内的位置,这样就算pop一个元素出来,也可以及时找到最小元素;
解析 由于这次需要我们有一个检索最小值的功能,所以我们这次创建两个栈,一个正常的栈xStack,一个用来存储较小值的栈minStack。
我们先给minStack存入一个很大的值——Integer.MAX_VALUE,用来后续的操作。
首先是实现push方法,我们的xStack就进行正常的push操作。我们的minStack则要将我们栈内的
元素和我们要存储的元素作比较,存入较小的值,我们的minStack就总能保证最小值在最顶层;
pop方法是删除栈顶的元素,我们就是直接使用Deque的pop即可,两个栈执行一次pop方法。
top方法我们是获取栈顶元素,我们的主栈xStack执行Deque的peek方法即可;
getMin方法是我们的检索栈中最小元素,我们就可以使用minStack的peek方法来实现;

这个题其实还挺有意思的,乍一看挺难的,但其实用对了方法会非常简单!
代码如下:

class MinStack {
public:
    /** initialize your data structure here. */
    MinStack() {
        minstack.push(INT_MAX);
    }
    stack<int>minstack,xstack;
    void push(int val) {
        xstack.push(val);
        minstack.push(min(minstack.top(),val));
    }
    
    void pop() {
        xstack.pop();
        minstack.pop();
    }
    
    int top() {
        return xstack.top();
    }
    
    int getMin() {
        return minstack.top();
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(val);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

非常简单的几行代码就可以实现这样的功能,很巧妙。自己画图就可以理解为什么可以这样push minstack,就可以达到这样的效果(当pop到xstack中最小的数字时,minstack中的top也发生了改变)。
还有一个要注意的点就是初始化minstack时,要在栈底放入一个非常大的数字,c++中是INT_MAX,这样就不会出错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值