Stack and Queue

A summary of stack and queue related problems from LeetCode with solutions in C++.

Problems:
232. Implement Queue using Stacks
225. Implement Stack using Queues
20. Valid Parentheses
1047. Remove All Adjacent Duplicates In String
150. Evaluate Reverse Polish Notation
239. Sliding Window Maximum
347. Top K Frequent Elements

1. 232. Implement Queue using Stacks

Problem: Implement a first in first out (FIFO) queue using only two stacks. The implemented queue should support all the functions of a normal queue (push, peek, pop, and empty).

Implement the MyQueue class:
(1) void push(int x) Pushes element x to the back of the queue.
(2) int pop() Removes the element from the front of the queue and returns it.
(3) int peek() Returns the element at the front of the queue.
(4) boolean empty() Returns true if the queue is empty, false otherwise.

Case 1:
Input: [“MyQueue”, “push”, “push”, “peek”, “pop”, “empty”], [[], [1], [2], [], [], []]
Output: [null, null, null, 1, 1, false]
Explanation:
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

Credit to Carl

// C++
class MyQueue {
public:
    stack<int> stackIn;
    stack<int> stackOut;
    MyQueue() {
    }
    // Push element x to the back of queue
    void push(int x) {
        stackIn.push(x);
    }
    // Removes the element from in front of queue and returns that element
    int pop() {
        // 只有当stOut为空的时候, 再从stIn里导入数据(导入stIn全部数据)
        if (stackOut.empty()) {
            // 从stackIn导入数据直到stackIn为空
            while (!stackIn.empty()) {
                stackOut.push(stackIn.top());
                stackIn.pop();
            }
        }
        int result = stackOut.top();
        stackOut.pop();
        return result;
    }
    // Get the front element
    int peek() {
        int result = this->pop(); // 直接使用已有的pop函数
        stackOut.push(result); // 因为pop函数弹出了元素result,再添加回去
        return result;
    }
    // Returns whether the queue is empty
    bool empty() {
        return stackIn.empty() && stackOut.empty();
    }
};

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

2. 225. Implement Stack using Queues

Problem: Implement a last-in-first-out (LIFO) stack using only two queues. The implemented stack should support all the functions of a normal stack (push, top, pop, and empty).

Implement the MyStack class:
(1) void push(int x) Pushes element x to the top of the stack.
(2) int pop() Removes the element on the top of the stack and returns it.
(3) int top() Returns the element on the top of the stack.
(4) boolean empty() Returns true if the stack is empty, false otherwise.

Case 1:
Input: [“MyStack”, “push”, “push”, “top”, “pop”, “empty”], [[], [1], [2], [], [], []]
Output: [null, null, null, 2, 2, false]
Explanation:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // return 2
myStack.pop(); // return 2
myStack.empty(); // return False

// C++
class MyStack1 {
public:
    queue<int> queue1;
    queue<int> queue2; // 辅助队列, 用来备份
    MyStack() {
    }
    // Push element x onto stack
    void push(int x) {
        queue1.push(x);
    }
    // Removes the element on top of the stack and returns that element
    int pop() {
        int size = queue1.size();
        // 将queue1 导入queue2, 但留下最后一个元素
        size--;
        while (size--) {
            queue2.push(queue1.front());
            queue1.pop();
        }
        // 留下的最后一个元素就是要返回的值
        int result = queue1.front();
        queue1.pop();
        // 再将queue2赋值给queue1
        queue1 = queue2;
        // 清空que2            
        while (!queue2.empty()) { 
            queue2.pop();
        }
        return result;   
    }
    // Get the top element
    int top() {
        return queue1.back();
    }
    // Returns whether the stack is empty
    bool empty() {
        return queue1.empty();
    }
};

class MyStack2 {
public:
    queue<int> queue;
    MyStack() {
    }
    // Push element x onto stack
    void push(int x) {
        queue.push(x);
    }
    // Removes the element on top of the stack and returns that element
    int pop() {
        int size = queue.size();
        // 将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部
        size--;
        while (size--) {
            queue.push(queue.front());
            queue.pop();
        }
        // 留下的最后一个元素就是要返回的值
        int result = queue.front();
        queue.pop();
        return result;   
    }
    // Get the top element
    int top() {
        return queue.back();
    }
    // Returns whether the stack is empty
    bool empty() {
        return queue.empty();
    }
};

3. 20. Valid Parentheses

Problem: Given a string s containing just the characters ‘(‘, ‘)’, ‘{‘, ‘}’, ‘[‘ and ‘]’, determine if the input string is valid.

An input string is valid if:
(1) Open brackets must be closed by the same type of brackets.
(2) Open brackets must be closed in the correct order.
(3) Every close bracket has a corresponding open bracket of the same type.

Case 1: Input: s = “()”, Output: true
Case 2: Input: s = “()[]{}”, Output: true
Case 3: Input: s = “(]”, Output: false

Credit to Carl

// C++
class Solution {
public:
    bool isValid(string s) {
        if (s.size() % 2 != 0) {return false;}
        stack<char> st;
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == '(') {
                st.push(')');
            } else if (s[i] == '{') {
                st.push('}');
            } else if  (s[i] == '[') {
                st.push(']');
            } else if (st.empty() || st.top() != s[i]) {
                // 第二种情况: 遍历字符串匹配的过程中, 发现栈里没有我们要匹配的字符
                // 第三种情况: 遍历字符串匹配的过程中, 栈已经为空了, 说明右括号没有找到对应的左括号
                return false;
            } else {
                // st.top() 与 s[i]相等, 栈弹出元素
                st.pop();
            }
        }
        // 第一种情况: 此时我们已经遍历完了字符串, 但是栈不为空, 说明有相应的左括号没有右括号来匹配
        return st.empty();
    }     
};

4. 1047. Remove All Adjacent Duplicates In String

Problem: You are given a string s consisting of lowercase English letters. A duplicate removal consists of choosing two adjacent and equal letters and removing them. We repeatedly make duplicate removals on s until we no longer can. Return the final string after all such duplicate removals have been made. It can be proven that the answer is unique.

Case 1: Input: s = “abbaca”, Output: “ca”, Explanation: For example, in “abbaca” we could remove “bb” since the letters are adjacent and equal, and this is the only possible move. The result of this move is that the string is “aaca”, of which only “aa” is possible, so the final string is “ca”.
Case 2: Input: s = “azxxzy”, Output: “ay”

Credit to Carl

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

class Solution2 {
public:
    string removeDuplicates(string s) {
        // s = "abbaca"
        string result;
        for(char s_char : s) {
            if(result.empty() || result.back() != s_char) {
                result.push_back(s_char);
            }
            else {
                result.pop_back();
            }
        }
        return result;
    }
};

5. 150. Evaluate Reverse Polish Notation

Problem: Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, *, and /. Each operand may be an integer or another expression. Note that division between two integers should truncate toward zero. It is guaranteed that the given RPN expression is always valid. That means the expression would always evaluate to a result, and there will not be any division by zero operation.

Case 1: Input: tokens = [“2″,”1″,”+”,”3″,”*”], Output: 9, Explanation: ((2 + 1) * 3) = 9
Case 2: Input: tokens = [“4″,”13″,”5″,”/”,”+”], Output: 6, Explanation: (4 + (13 / 5)) = 6
Case 3: Input: tokens = [“10″,”6″,”9″,”3″,”+”,”-11″,”*”,”/”,”*”,”17″,”+”,”5″,”+”], Output: 22

Credit to Carl

// C++
class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<long long> st; 
        for (int i = 0; i < tokens.size(); i++) {
            if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
                long long num1 = st.top();
                st.pop();
                long long num2 = st.top();
                st.pop();
                if (tokens[i] == "+") {st.push(num2 + num1);}
                if (tokens[i] == "-") {st.push(num2 - num1);}
                if (tokens[i] == "*") {st.push((long)num2 * (long)num1);}
                if (tokens[i] == "/") {st.push(num2 / num1);}
            } else {
                // stoll: convert string to long long
                st.push(stoll(tokens[i]));
            }
        }
        int result = st.top();
        st.pop(); // 把栈里最后一个元素弹出
        return result;
    }
};

6. 239. Sliding Window Maximum

Problem: You are given an array of integers nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.

Case 1: Input: nums = [1,3,-1,-3,5,3,6,7], k = 3, Output: [3,3,5,5,6,7], Explanation:
Window position                               Max
———————                               ——
[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
Case 2: Input: nums = [1], k = 1, Output: [1]

Credit to Carl

// C++
class Solution {
private:
    class MyQueue {
    public:
        // front: 出口, back: 入口
        // 使用deque来实现单调队列
        deque<int> que;
        // 每次弹出的时候, 比较当前要弹出的数值是否等于队列出口元素的数值
        // 如果相等则弹出, 同时pop之前判断队列当前是否为空
        void pop(int val) {
            if (!que.empty() && val == que.front()) {
                que.pop_front();
            }
        }
        // 如果push的数值大于入口元素的数值, 那么就将队列后端的数值弹出
        // 直到push的数值小于等于队列入口元素的数值为止
        // 保持队列里的数值是单调从大到小
        void push(int value) {
            while (!que.empty() && value > que.back()) {
                que.pop_back();
            }
            que.push_back(value);
        }
        // 查询当前队列里的最大值, 直接返回队列前端
        int front() {
            return que.front();
        }
    };
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        MyQueue que;
        vector<int> result;
        // 先将前k的元素放进队列
        for (int i = 0; i < k; i++) { 
            que.push(nums[i]);
        }
        result.push_back(que.front()); // result 记录前k的元素的最大值
        for (int i = k; i < nums.size(); i++) {
            que.pop(nums[i-k]); // 滑动窗口移除最前面元素
            que.push(nums[i]);  // 滑动窗口前加入最后面的元素
            result.push_back(que.front()); // 记录对应的最大值
        }
        return result;
    }
};

7. 347. Top K Frequent Elements

Problem: Given an integer array nums and an integer k, return the k most frequent elements. You may return the answer in any order.

Case 1: Input: nums = [1,1,1,2,2,3], k = 2, Output: [1,2]
Case 2: Input: nums = [1], k = 1, Output: [1]

Credit to Carl

// C++
// Time complexity: O(nlogk)
// Space complexity: O(n)
class Solution {
public:
    // 小顶堆
    class myComparison {
    public:
        bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
            return lhs.second > rhs.second;
        }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) {
        // 要统计元素出现频率
        // key: nums[i]
        // value: numbers of nums[i]
        unordered_map<int, int> map;
        for (int i = 0; i < nums.size(); i++) {
            map[nums[i]]++;
        }
        // 对频率排序, 定义一个小顶堆,大小为k 
        priority_queue< pair<int, int>, vector<pair<int, int>>, myComparison > pri_que;
        // 用固定大小为k的小顶堆, 扫面所有频率的数值
        for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
            pri_que.push(*it);
            // 如果堆的大小大于了k, 则队列弹出, 保证堆的大小一直为k
            if (pri_que.size() > k) { 
                // pop出小顶堆中最小的元素
                pri_que.pop();
            }
        }
        // 找出前k个高频元素, 因为小顶堆先弹出的是最小的, 所以倒序来输出到数组
        vector<int> result(k);
        for (int i = k - 1; i >= 0; i--) {
            // first means key
            // second means value
            result[i] = pri_que.top().first;
            pri_que.pop();
        }
        return result;
    }
};

Back to top of page