leecode栈和队列相关题目c++

本文介绍了使用C++解决LeetCode中关于栈和队列的题目,包括用栈实现队列、用队列实现栈、有效括号检查、删除重复字符、逆波兰表达式求值、滑动窗口最大值和找出前K个高频元素。通过具体的思路和代码解析,详细阐述了解题方法。
摘要由CSDN通过智能技术生成

简单:

232 用栈实现队列

https://leetcode.cn/problems/implement-queue-using-stacks/submissions/
在这里插入图片描述
在这里插入图片描述

解答:
思路:用两个栈来实现,倒一下即刻。

class MyQueue {
public:
    stack<int> in;
    stack<int> out;
    MyQueue() {

    }
    
    void push(int x) {
        in.push(x);
    }
    
    int pop() {
        if(out.empty()){
            while(!in.empty()){
                out.push(in.top());
                in.pop();
            }
        }
        int reslut = out.top();
        out.pop();
        return reslut;
    }
    
    int peek() {
        int reslut = this->pop();
        out.push(reslut);  //因为pop函数弹出了元素res,所以再添加回去
        return reslut;

    }
    
    bool empty() {
        return in.empty() && out.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();
 */

225. 用队列实现栈

在这里插入图片描述
在这里插入图片描述
解答:
思路:
两个队列来实现栈。其中一个队列是用来暂存数据的。也就是先将队列1中的元素都放到队列2中,只留下最后一个元素作为输出,然后在讲队列2中的元素放回队列1后,将队列2清空;反复此操作。

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

    }
    
    void push(int x) {
        q1.push(x);
    }
    
    int pop() {
        int size=q1.size();
        while(size!=1){
            q2.push(q1.front());
            q1.pop();
            size--;
        }
        int result=q1.front();
        q1.pop();
        q1=q2;
        while(!q2.empty()){
            q2.pop();
        }
        return result;
    }
    
    int top() {
        return q1.back();  //返回最末元素
    }
    
    bool empty() {
        return q1.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. 有效的括号

在这里插入图片描述
在这里插入图片描述

解答:
思路
碰见一个左括号,就将其对应的右括号放进栈中。如果栈为空,或者遍历到的右括号不等于栈顶元素,那就是false。如果左括号找到了对应的右括号,就弹出栈即可。
代码

class Solution {
public:
    bool isValid(string s) {
        stack<int> tmp;
        for(int i=0;i<s.size();i++){
            if(s[i]=='(') tmp.push(')');
            else if(s[i]=='{') tmp.push('}');
            else if(s[i]=='[') tmp.push(']');
            else if(tmp.empty() || s[i]!=tmp.top()) return false;
            else
               tmp.pop();
        }
    return tmp.empty();
    }
};

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

在这里插入图片描述
解答:
法一
思路:将字符串本身当作栈。将字符放入栈中,比较栈顶元素和外面遍历的元素是否相等,相等就弹出栈,不相等就将栈外元素压入栈。当然如果是第一个元素,就直接讲该元素压入栈。最后返回就返回该作为栈的字符串即可。

class Solution {
public:
    string removeDuplicates(string s) {
        string tmp;
        for(int i=0;i<s.size();i++)
        {
            if(tmp.empty() || tmp.back()!=s[i])
            {
                tmp.push_back(s[i]);
                }
            else {
                tmp.pop_back();
            }
                
        }
        return tmp;
        }
        
};

法二
思路:新创建一个字符类型的栈,与法一同样原理,外面遍历的元素如果和栈顶元素相等,就弹出栈顶元素。这样输出的时候,不能直接输出栈,因为返回值类型不同,需要将栈中的元素取出(此时是反序的),再逆序。
代码:

class Solution {
public:
    string removeDuplicates(string s) {
        stack<char> tmp;
        for(int i=0;i<s.size();i++)
        {
            if(tmp.empty() || tmp.top()!=s[i])
            {
                tmp.push(s[i]);
                }
            else {
                tmp.pop();
            }     
        }
        string result="";
        while(!tmp.empty()){
            result += tmp.top();
            tmp.pop();
        }
        reverse (result.begin(), result.end()); // 反转

        return result;
        }
        
};

150. 逆波兰表达式求值

在这里插入图片描述
在这里插入图片描述

思路:与上一题的思路是一样的,只是不移除元素,将栈顶两个元素弹出,做相应的运算,然后再将运算后的结果放回栈中,最终要的结果就是栈顶元素。(记得要类型转换string->int)
代码:

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> tmp;
        for(int i=0;i<tokens.size();i++){
            if(tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*"  || tokens[i] == "/" ){
                int a1=tmp.top();
                tmp.pop();
                int a2=tmp.top();
                tmp.pop();
                if(tokens[i] == "+" ){
                    tmp.push(a1+a2);
                }
                else if(tokens[i] == "-" ){
                    tmp.push(a2-a1);
                }
                else if(tokens[i] == "*" ){
                    tmp.push(a1*a2);
                }
                else if(tokens[i] == "/" ){
                    tmp.push(a2/a1);
                }
            }
            else{
                tmp.push(stoi(tokens[i]));  // stoi()函数为string.h中的,将string类型转化为int类型
            }
        }
        return tmp.top();
        tmp.pop();
    }
};

239. 滑动窗口最大值

在这里插入图片描述

解答:
思路:
总思路:在双向队列中,只存放k个数据(这个数据是nums中元素对应的索引),并且这写数据是递减排序的,每次取出开头front的数据即为最大数据。
过程:
1、创建一个双向队列,因为双向队列对前端数据和后端数据可以进行弹出操作。
2、判断是否在滑动范围内。
3、保证队列是递减队列,即如果当前的数据比队列中最后一个位置对应的数据还要大,那就说明最后一个(back)元素不可能是最大元素,就弹出;然后再重复此过程,判断它(back)前面的数据是否小于当前数据,小于,就还弹出。
4、将当前元素对应的位置(索引)放进队列。
5、判断队列中是否已经达到了k个元素,到了就该取最大值了,也就是队列第一个元素对应的数据。

代码:

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        deque<int> d;  //创建双向队列
        vector<int> result;
        for(int i=0;i<nums.size();i++){
            while(d.size() && i-k+1>d.front()) {d.pop_front();} //判断是否在滑动范围内。
            while(d.size() && nums[i]>=nums[d.back()]) {d.pop_back();} //保证队列是递减队列
            d.push_back(i);
            if(i>=k-1){result.push_back(nums[d.front()]);}//判断队列中是否已经达到了k个元素,到了就该取最大值了
        }
        return result; 
    }
};

347. 前 K 个高频元素

在这里插入图片描述

解答:
思路:
1、首先涉及到需要存到一个值和其对应的频率,可以想到可以用map来存放。所以首先使用一个无序的map把数组中的值及其对应的频率保存起来。
2、其次需要根据这些频率进行排序,并输出值。可以想到大顶堆和小顶堆来做。此时我们选用小顶堆,此时为了方便,可以直接使用priority_queue优先队列来存放(该队列优先级最高的先弹出)。

涉及到的基础知识罗列:
1、operator重载运算符

语法:
函数类型 operator 运算符名称(或操作符)(参数列表)
{
    函数体;
}

2、priority_queue优先队列
优先级高的元素先出队列,并非按照先进先出的要求.类似一个堆(heap).

priority_queue<Type, Container, Functional>
Type:数据类型
Container:为保存数据的容器
Functional:为元素比较方式

3、unordered_map
无序映射(Unordered maps)是用于存储键值和映射值组合成的元素的关联容器,并允许基于其键快速检索各个元素。
在unordered_map中,键值通常用于唯一地标识元素,而映射值是具有与该键关联的内容的对象。键的类型和映射的值可能会有所不同。
头文件:

#include < unordered_map >

代码:

class Solution {
public:
    //构造小顶堆
    class compare_Function{
    public:
        bool operator()(const pair<int,int>& p1,const pair<int,int>& p2){
            return p1.second>p2.second;
        }
    };
    vector<int> topKFrequent(vector<int>& nums, int k) {
        
        unordered_map <int,int> map; 
        for(int i=0;i<nums.size();i++){
            map[nums[i]]++;  //用来存放每个数据的频率
        }
        priority_queue<pair<int,int>,vector<pair<int,int>>,compare_Function> que;
        for(unordered_map<int,int>::iterator it=map.begin();it!=map.end();it++){
            que.push(*it);
            if(que.size()>k){
                que.pop();
            }
        }
        //由于是小顶堆,需要倒序输出
        vector<int> result(k);
        for(int i=k-1;i>=0;i--){
            result[i]=que.top().first;
            que.pop();
        }
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值