代码随想录训练营第十一天——用栈实现队列,用队列实现栈,有效括号,删除字符串中的相邻重复项

栈和队列基础理论

  • 队列是先进先出,栈是先进后出
  • 栈和队列是SGI STL里面的数据结构

  • 栈提供push,pop,top等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不提供迭代器(iterator)。 不像是set 或者map 提供迭代器iterator来遍历所有元素。
  • 栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说我们可以控制使用哪种容器来实现栈的功能)。所以STL中栈往往不被归类为容器,而被归类为container adapter(容器适配器)。
  • 栈的底层实现可以是vector,deque,list, 主要就是数组和链表的底层实现。
  • 常用的SGI STL,如果没有指定底层实现的话,默认是以deque为缺省情况下栈的低层结构。deque是一个双向队列,只要封住一段,只开通另一端就可以实现栈的逻辑了。
  • 栈里面的元素在内存中不一定是连续分布的:栈是容器适配器,底层容器使用不同的容器,导致栈内数据在内存中不一定是连续分布的;缺省情况下,默认底层容器是deque,deque在内存中的数据分布是不连续的。
  • 栈可以指定为vector为底层实现,初始化栈如下:
std::stack<int, std::vector<int> > third;  // 使用vector为底层容器的栈

队列

  • 队列是先进先出的数据结构,同样不允许有遍历行为,不提供迭代器。
  • 队列提供push,pop,front,back等接口
  • SGI STL中队列也是以deque为缺省情况下的底部结构。
  • 队列也可以指定list 为起底层实现,初始化queue如下:
std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列

leetcode 232.用栈实现队列

题目链接:栈实现队列
使用栈来模式队列的行为,需要两个栈,输入栈和输出栈

class MyQueue {
public:
    stack<int> stin;
    stack<int> stou;  
    MyQueue() {

    }
    
    void push(int x) {
        stin.push(x);
    }
    
    int pop() {
         // 只有当stOut为空的时候,再从stIn里导入数据(导入stIn全部数据)
        if(stou.empty())
        {
        while(!stin.empty())
        {
            stou.push(stin.top());
            stin.pop();
        }
        }
        int result=stou.top();
        stou.pop();
        return result;
    }
    
    int peek() {
        int result=this->pop(); // 直接使用已有的pop函数
        stou.push(result);   //因为pop函数弹出了元素res,所以再添加回去
        return result;
    } 
    bool empty() {
     return stin.empty() && stou.empty();
    }
};

leetcode 225. 用队列实现栈

题目链接:队列实习栈

使用两个队列实现栈:

class MyStack {
public:
    queue<int> que1;
    queue<int> que2; // 辅助队列,用来备份
   
    MyStack() {

    }

  
    void push(int x) {
        que1.push(x);
    }

      int pop() {
        int size = que1.size();
        size--;
        while (size--) { // 将que1 导入que2,但要留下最后一个元素
            que2.push(que1.front());
            que1.pop();
        }

        int result = que1.front(); // 留下的最后一个元素就是要返回的值
        que1.pop();
        que1 = que2;            // 再将que2赋值给que1
        while (!que2.empty()) { // 清空que2
            que2.pop();
        }
        return result;
    }

     int top() {
        return que1.back();
    }

      bool empty() {
        return que1.empty();
    }
};

使用一个队列实现栈

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

    }
    void push(int x) {
        que.push(x);
    }
   
    int pop() {
        int size = que.size();
        size--;
        while (size--) { // 将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部
            que.push(que.front());
            que.pop();
        }
        int result = que.front(); // 此时弹出的元素顺序就是栈的顺序了
        que.pop();
        return result;
    }

    int top() {
        return que.back();
    }

    bool empty() {
        return que.empty();
    }
};

leetcode 20. 有效的括号

题目链接:有效的括号
字符串里的括号不匹配有三种情况:

  • 第一种情况,字符串里左方向的括号多余了 ,所以不匹配。
  • 第二种情况,括号没有多余,但是括号的类型没有匹配上。
  • 第三种情况,字符串里右方向的括号多余了,所以不匹配。
    则对应以下三种情况:
  • 第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false。
  • 第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符,所以return false。
  • 第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号,return false。
    则考虑左括号和右括号全都匹配了的情况,就是字符串遍历完之后,栈是空的,就说明全都匹配了。
class Solution {
public:
    bool isValid(string s) {
        if (s.size() % 2 != 0) return false; // 如果s的长度为奇数,一定不符合要求
        stack<char> st;
        for(int i=0;i<s.size();i++)
        {
             // 第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号 return false
            // 第二种情况:遍历字符串匹配的过程中,发现栈里没有我们要匹配的字符。所以return false
            if(s[i]=='(') st.push(')');
            else if(s[i]=='{') st.push('}');
            else if(s[i]=='[') st.push(']');
            else if(st.empty()||s[i]!=st.top()) return false;
            else st.pop();
        }
        // 第一种情况:此时已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false,否则就return true
         return st.empty();  
    }
};

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

题目链接:删除字符串中的所有相邻重复项
采用栈的代码:

class Solution {
public:
    string removeDuplicates(string S) {
        stack<char> st;
        for (char s : S) {
            if (st.empty() || s != st.top()) {
                st.push(s);
            } else {
                st.pop(); // s 与 st.top()相等的情况
            }
        }
        string result = "";
        while (!st.empty()) { // 将栈中元素放到result字符串汇总
            result += st.top();
            st.pop();
        }
        reverse(result.begin(), result.end()); // 此时字符串需要反转一下
        return result;
    }
};

采用字符串直接作栈的代码:

class Solution {
public:
    string removeDuplicates(string S) {
        string result;
        for(char s : S) {
            if(result.empty() || result.back() != s) {   //找字符串的末尾用result.back()
                result.push_back(s);
            }
            else {
                result.pop_back();   //注意pop_back与push_back的不同,一个函数里有参数,一个无参数
            }
        }
        return result;
    }
};

你可能感兴趣的:(leetcode,算法,链表)