刷题6--栈、队列

本文介绍了如何在C++中使用栈和队列来实现特定功能,如用栈实现队列、用队列实现栈,并给出了相关LeetCode题目,如有效的括号、删除重复项等。同时,讨论了C++标准库中的stack和queue容器适配器,以及它们的操作函数,如push、pop和top。此外,还涉及到了优先级队列在解决前K个高频元素问题中的应用。
摘要由CSDN通过智能技术生成

目录

 函数调用

 232、用栈实现队列

225.、用队列实现栈

20、有效的括号

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

150、逆波兰表达式求值

stol()将字符串其作为long int类型的值返回。

stoll()将字符串其作为long long int类型的值返回。

239. 滑动窗口最大值

347.前 K 个高频元素

优先级队列


这个都知道,队列是先进先出,栈是先进后出

但是要知道--栈和队列进和出是push和pop

C++中stack、queue 是容器么?

        不算是容器,因为其是靠其他容器来实现的,具体使用何种容器来实现栈、队列是可选择的,所以栈只能算是container adapter(容器适配器),不算容器

我们使用的STL中stack、queue是如何实现的?

          vector,deque,list都可以,主要是数组和链表的实现

stack 提供迭代器来遍历stack、queue空间么?

           不提供

 函数调用

 文中涉及到的常用函数调用

stackpush、pop、top
queuepush、pop、front、back
priority_queuepush、pop、top
dequepush_front、push_back、pop_front、pop_back、front、back

 232、用栈实现队列

232. 用栈实现队列 - 力扣(Leetcode)

为什么不直接使用pop函数,而使用top函数

pop(), 返回void,top(),返回栈顶的引用。

C++中对栈的操作函数pop()和top()的区别_s.pop()_初啾的博客-CSDN博客

 C++中stack的pop()函数返回值_stack pop_code的魅力的博客-CSDN博客

两个栈,一个输入一个输出

尤其要注意出队列是,当栈2为空,循环将栈1的元素压入栈2;不为空就出栈,并将栈中此元素清掉

class MyQueue {
public:
    stack<int> StaIn;
    stack<int> StaOut;
    MyQueue() {
        
    }
    
    void push(int x) {
        StaIn.push(x);
    }
    
    int pop() {
        if(StaOut.empty()) {
            while(!StaIn.empty()) {
                StaOut.push(StaIn.top());
                StaIn.pop();
            }
        }
        int result = StaOut.top();
        StaOut.pop();
        return result;
    }
    
    int peek() {
        int PeekResult = pop();
        StaOut.push(PeekResult);
        return PeekResult;
    }
    
    bool empty() {
        if(StaIn.empty() && StaOut.empty()) {
            return true;
        } else return false;
    }
};

/**
 * 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();
 */

225.、用队列实现栈

225. 用队列实现栈 - 力扣(Leetcode)

可以用一个队列实现栈,尤其需要注意出栈要怎么写

只用将最后进入队列的元素保留,其他队列元素全都重新填入队列,并将队列此元素清除掉(pop)

也可以使用两个队列实现栈,需要注意出栈怎么写

que1留下最后一个元素,将que1剩余元素导入que2,que1留下最后一个元素就是最后一个元素;

接着将que2赋值给que1,将que2清空

class MyStack {
public:
    queue<int> que1;
    queue<int> que2; // 辅助队列,用来备份
    /** Initialize your data structure here. */
    MyStack() {

    }

    /** Push element x onto stack. */
    void push(int x) {
        que1.push(x);
    }

    /** Removes the element on top of the stack and returns that element. */
    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;
    }

    /** Get the top element. */
    int top() {
        return que1.back();
    }

    /** Returns whether the stack is empty. */
    bool empty() {
        return que1.empty();
    }
};

20、有效的括号

20. 有效的括号 - 力扣(Leetcode)

使用解决有效的括号问题

class Solution {
public:
//有三种情况返回false 1:左括号多了,2:右括号多了,3:左右括号不匹配
    bool isValid(string s) {
        stack<char> Sta;
        for(char c : s) {
            if(c == '(') Sta.push(')');
            else if (c == '{') Sta.push('}');
            else if (c == '[') Sta.push(']');
            else if (Sta.empty() || c != Sta.top()) return false;//2和3
            else Sta.pop();
        }
        return Sta.empty();//此时返回false是1,返回true就是对了
    }
};

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

1047. 删除字符串中的所有相邻重复项 - 力扣(Leetcode)

这个题也是使用进行解决,匹配问题是栈的强项

递归调用就是会把函数的局部变量、参数和返回地址等压入栈中,但在企业项目开发中,尽量不要使用递归,容易无限递归

class Solution {
public:
    string removeDuplicates(string s) {
        stack<char> sta;//创建sta
        //遍历string s
        for (char sf : s) {
            //如果是空的和s中的字符不等于st的字符,就往st里放字符
	            //其他种情况就要pop
            if (sta.empty() || sf != sta.top()) {
                sta.push(sf);
            } else {
                sta.pop();
            }
        }
        //将栈中元素放到结果result字符串中
        string result = "";
        while (!sta.empty()) {
            result += sta.top();
             sta.pop();
        }
        //翻转一下字符串
        reverse(result.begin(),result.end());
        return result;
    }
};

150、逆波兰表达式求值

150. 逆波兰表达式求值 - 力扣(Leetcode)

stol()将字符串其作为long int类型的值返回。

stoll()将字符串其作为long long int类型的值返回。

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        // 力扣修改了后台测试数据,需要用longlong
        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(num2 * num1);
                if (tokens[i] == "/") st.push(num2 / num1);
            } else {
                st.push(stoll(tokens[i]));
            }
        }

        int result = st.top();
        st.pop(); // 把栈里最后一个元素弹出(其实不弹出也没事)
        return result;
    }
};

239. 滑动窗口最大值

239. 滑动窗口最大值 - 力扣(Leetcode)

使用单调队列的经典题目

自己实现一个单调队列,滑动窗口就是这个队列,具有以下功能:

1、pop滑动窗口删除元素

2、push滑动窗口添加元素

3、front滑动窗口返回最大值

维护滑动窗口有可能成为最大值的一个序列,主要就是维持出口的元素

如果push一个元素,而之前的元素小于这个元素,就将原来的元素pop掉

如果pop的元素是当前队列的出口元素就pop,否则不动

class Solution {
private:
    class MyQueue { //单调队列(从大到小)
    public:
        deque<int> que; // 使用deque来实现单调队列
        // 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。
        // 同时pop之前判断队列当前是否为空。
        void pop(int value) {
            if (!que.empty() && value == que.front()) {
                que.pop_front();
            }
        }
        // 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。
        // 这样就保持了队列里的数值是单调从大到小的了。
        void push(int value) {
            while (!que.empty() && value > que.back()) {
                que.pop_back();
            }
            que.push_back(value);

        }
        // 查询当前队列里的最大值 直接返回队列前端也就是front就可以了。
        int front() {
            return que.front();
        }
    };
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        MyQueue que;
        vector<int> result;
        for (int i = 0; i < k; i++) { // 先将前k的元素放进队列
            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;
    }
};

347.前 K 个高频元素

347. 前 K 个高频元素 - 力扣(Leetcode)

 这个题还是挺难的,再写一遍不一定可以写对

1.统计元素出现频率   map

2.对频率排序     优先级队列

3.找出前k个高频元素

那么为什么不用快速排序方法,是因为需要将map转换为vector的结构

因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。

class Solution {
public:
    //排序-小顶堆
    class mycomparison {
    public:
        bool operator() (const pair<int, int> &a, const pair<int, int> &b) {
            return a.second > b.second;
        }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) {
        //1.统计出现频率
        unordered_map<int, int> map;
        for (int i = 0; i < nums.size(); i++) {
            map[nums[i]]++;
        }
        //2.对频率进行排序
        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);
            if (pri_que.size() > k) {
                pri_que.pop();
            }
        }
        //3.找出结果,化成vector
        vector<int> result(k);
        for (int j = k - 1; j >= 0; j--) {
            result[j] = pri_que.top().first;
            pri_que.pop();
        }
        return result;
    }
};

优先级队列

具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的,而堆是由二叉树实现的

优先级队列(priority_queue):有大顶堆和小顶堆,都是一颗完全二叉树,其中大顶堆中每个结点的值都不小于其左右孩子的值(堆头是最大元素),小顶堆中每个结点的值都不大于其左右孩子的值(堆头是最小元素)

priority_queue<Type, Container, Functional>

Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式。Functional默认大顶堆,容器类型默认vector

//升序队列
priority_queue <int,vector<int>,greater<int> > q;
//降序队列
priority_queue <int,vector<int>,less<int> >q;

//greater和less是std实现的两个仿函数(就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了)

 C++优先级队列_莓关系的博客-CSDN博客

模拟实现优先级队列超详解(C++)_c++优先队列底层实现_今天也要写bug的博客-CSDN博客

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值