代码随想录刷题day10|LeetCode232 用栈实现队列、LeetCode225 用队列实现栈、LeetCode20 有效的括号、LeetCode1047 删除字符串中的所有相邻重复项

栈和队列的理论基础

关于两个数据结构的底层实现,详细介绍可见代码随想录的学习网站

栈和队列不是容器,而是容器适配器,底层可以自由控制使用其他容器来实现栈和队列的功能。

-栈提供push 和 pop 等等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能也不提供迭代器(iterator)。 不像是set 或者map 提供迭代器iterator来遍历所有元素。

栈的内部结构,栈的底层实现可以是vector,deque,list, 主要就是数组和链表的底层实现。

指定vector为栈的底层实现,初始化语句如下:

    std::stack<int, std::vector<int> > third;  // 使用vector为底层容器的栈

-队列中先进先出的数据结构,队列同样不允许有遍历行为,不提供迭代器

指定list 为起底层实现,初始化queue的语句如下:

    std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列

LeetCode232 用栈实现队列

力扣题目链接

思考:

比较简单的一题,没有涉及算法。把握住栈是先进后出,要实现队列的先进先出。

代码说明在代码块注释中。需要注意的是,队列的弹出操作最终是从出栈中弹出,所以做队列pop操作时需要先确定出栈是否不为空若为空则需要将入栈的元素倒进出栈中。

再者就是,栈的pop和push操作都是void函数,不会返回一个具体的元素,以下写法是错误的:

    int temp=stackIn.pop();

而top函数可以返回一个具体的元素,但是不具备从栈中删除元素的能力。 

我的代码:

class MyQueue {
public:
    //需要两个栈,一个进栈一个出栈
    stack<int> inTo;
    stack<int> outTo;
    MyQueue() {
        
    }
    
    void push(int x) {
        inTo.push(x);
    }
    
    int pop() {
        //因为队列的弹出操作最终是从出栈中弹出,所以做队列pop操作时需要先确定出栈是否不为空,若为空则需要将入栈的元素倒进出栈中
        if(outTo.empty()){
            while(!inTo.empty()){
                int temp=inTo.top();
                inTo.pop();
                outTo.push(temp);
            }
            int temp=outTo.top();
            outTo.pop();
            return temp;
        }
        //出栈不为空时可以直接从出栈弹出
        else 
        {
            int temp=outTo.top();
            outTo.pop();
            return temp;
        }
    }
    //获取队列顶部元素,和队列弹出操作类似,但是并不会将元素从队列中弹出删除
    int peek() {
        //注意相似功能的复用,直接使用已有的pop函数
        int temp = this->pop(); 
        // 因为pop函数弹出了元素res,所以再添加回去
        outTo.push(temp); 
        return temp;
    }
    //两个栈均空时才算队列空
    bool empty() {
        if(inTo.empty()&&outTo.empty())
            return true;
        else return false;
    }
};
  • 时间复杂度: push和empty为O(1), pop和top为O(n)
  • 空间复杂度: O(n)

225. 用队列实现栈

力扣题目链接

思考:也是一道不涉及算法的题,但是相比于用栈实现队列来说会稍微有些绕,主要体现在pop操作的实现。看下图:

分为fin是否为空两种情况

我的代码:

class MyStack {
public:
    queue<int> fin;
    queue<int> mid;
    MyStack() {

    }
    
    void push(int x) {
        fin.push(x);
    }
    //
    int pop() {
        if(fin.empty()){
            int temp=mid.front();
            mid.pop();
            while(!mid.empty()){
                fin.push(temp);
                temp=mid.front();
                mid.pop();
            }
            return temp;
        }
        else{
            int temp=fin.front();
            fin.pop();
            while(!fin.empty()){
                mid.push(temp);
                temp=fin.front();
                fin.pop();
            }
            return temp;
        }
    }
    
    int top() {
        int temp=this->pop();
        this->push(temp);
        return temp;
    }
    
    bool empty() {
        if(fin.empty()&&mid.empty())
            return true;
        else return false;
    }
};
  • 时间复杂度: pop为O(n),top为O(n),其他为O(1)
  • 空间复杂度: O(n)

20. 有效的括号

力扣题目链接

思考:

很简单的一道用栈解决的题。因为栈先进后出的特性,和括号匹配是适配的,外层的括号后匹配,内层的括号先匹配。

所以思路就是:循环遍历字符串,遇到所有左括号都压入栈中,遇到匹配的右括号就将左括号弹出栈。具体的边界情况处理见代码块注释。

我的代码:

class Solution {
public:
    bool isValid(string s) {
        stack<char> myStack;
        //循环遍历字符串,遇到所有左括号都压入栈中,遇到匹配的右括号就将左括号弹出栈
        for(int i=0;i<s.size();i++){
            if(s[i]=='('||s[i]=='{'||s[i]=='[')
                myStack.push(s[i]);
        //如果经过上一步压栈操作之后,此时栈仍为空,说明循环遍历到的是右括号,且没有对应的左括号与右括号相匹配,可以直接返回false
            if(!myStack.empty()){
        //栈不为空时,继续判断后面遇到的右括号能否和左括号正确匹配,匹配正确就把左括号弹出栈,不正确说明没有对应的左括号在栈中,直接返回false
                if(s[i]==')'&&myStack.top()=='(')
                    myStack.pop();
                else if(s[i]==')'&&myStack.top()!='(')
                    return false;
                if(s[i]=='}'&&myStack.top()=='{')
                    myStack.pop();
                else if(s[i]=='}'&&myStack.top()!='{')
                    return false;
                if(s[i]==']'&&myStack.top()=='[')
                    myStack.pop();
                else if(s[i]==']'&&myStack.top()!='[')
                    return false;
            }
            else return false;
        }
    //最后判断空栈说明所有括号都匹配上了,反之不匹配
        if(myStack.empty())
            return true;
        else return false;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

1047. 删除字符串中的所有相邻重复项

力扣题目链接

思考:

消消乐(?

这道题也不难,利用栈先进后出的性质,栈可以作为 判断是否出现两个相邻且相同的字母 的工具。一边遍历字符串,一边将元素压入栈中;当栈顶元素和当前遍历到的字符串元素相同时,在弹出栈顶元素的同时,利用双指针法修改原字符串s。具体的边界情况处理见代码块注释。

注意最后更改新字符串的长度。

我的代码:

class Solution {
public:
    string removeDuplicates(string s) {
        //还是用栈解决,两个相同的字母在栈中相遇时,就将它俩全部弹出栈
        //同时用双指针法,对应更新字符串s包含的字符
        stack<char> myStack;
        int j=0;
        for(int i=0;i<s.size();i++){
        //栈空时直接将字符压入栈中
            if(myStack.empty()){
                myStack.push(s[i]);
                s[j++]=s[i];
            }
        //否则先判断此时栈顶元素和循环到的串元素是否相同,相同则弹出栈且不更新字符串,不相同则压入栈
            else{
                char temp=myStack.top();
                if(temp==s[i]){
                    myStack.pop();
                    j--;
                }
                else{
                    myStack.push(s[i]);
                    s[j++]=s[i];
                }
            }
        }
    //最后更新字符串长度
        s.resize(j);
        return s;
    }
};
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

 *文章是本人刷题过程中的一些笔记和理解,记录的解析不一定足够清晰,也可能存在本人暂未意识到的错误,如有问题欢迎大家指出。文章中学习到的解法来自代码随想录的B站视频(栈和队列1~4)以及代码随想录的学习网站

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值