剑指offer<数据结构>------------队栈

用两个栈实现队列

题目来源:牛客网

1、问题描述

描述
用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。
数据范围: n\le1000n≤1000
要求:存储n个元素的空间复杂度为 O(n)O(n) ,插入与删除的时间复杂度都是 O(1)O(1)

2、思路解析

先将数据压入栈1,因为先进后出,所以出来的数据是反向的,所以又将栈1中数据压入栈2,出栈顺序为刚开始入栈的顺序。提前说明在压入栈2前要保证栈2为NULL,因为栈2不为NULL时就插入数据就会导致前边的数据进去的早,出来的完,就会导致顺序反向。
看一个例子:

在这里插入图片描述
在这里插入图片描述
可以看出栈2不为NULL时就插入数据,导致出栈顺序就会和入栈顺序不和,这就不符合队列的先进先出的性质

3、代码实现

class Solution
{
public:
    void push(int node) {
        stack1.push(node);
    }
    int pop() {
        //将栈中元素插入到栈2中
        //直到栈2为NULL插入数据
        if(stack2.empty()){
            while(!stack1.empty()){
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
       int num=stack2.top();
        stack2.pop();
        return num;
    }
private:
    stack<int> stack1;
    stack<int> stack2;
};

包含min函数的栈

题目来源:牛客网

1、问题描述

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数,输入操作时保证 pop、top 和 min 函数操作时,栈中一定有元素。

此栈包含的方法有:
push(value):将value压入栈中
pop():弹出栈顶元素
top():获取栈顶元素
min():获取栈中最小元素

数据范围:操作数量满足 0 \le n \le 300 \ 0≤n≤300 ,输入的元素满足 |val| \le 10000 \ ∣val∣≤10000
进阶:栈的各个操作的时间复杂度是 O(1)\ O(1) ,空间复杂度是 O(n)\ O(n)
在这里插入图片描述

2、思路解析

底层还是stack来存储数据,但是最小数据使用的有序容器 set map都是有序容器,但是set不允许数据重复所以不能使用,那么map怎么做到的呢?将数据作为map的key,数据出现的次数作为values值当删除元素,只–出现的次数,当对应的次数到1时就删除数据,最小值就是map首元素的key值,直接返回就行。

3、代码实现

class Solution {
    //栈+优先级队列
    map<int,int> mp;
    stack<int> s;
    
public:
    void push(int value) {
        s.push(value);
        mp[value]++;
        
    }
    void pop() {
        //删除栈顶元素同时删除hash中元素
        if(mp[s.top()]==1){
            //直接删除
            mp.erase(s.top());
        }else{
            mp[s.top()]--;
        }
        s.pop();
        
    }
    int top() {
        return s.top();
        
    }
    int min() {
        return mp.begin()->first;
        
    }
};

栈的压入、弹出序列

题目来源:牛客网

1、问题描述

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

  1. 0<=pushV.length == popV.length <=1000
  2. -1000<=pushV[i]<=1000
  3. pushV 的所有数字均不相同

2、思路解析

先将push数组中元素压入栈中直到栈顶元素等于popV的第一个元素,当栈顶元素不等于popV数组下一个元素就压入push数据的下一个元素
当遍历完push数组,就返回s.empty(),栈为NULL就表示这一堆数组就是入栈何出栈的顺序。

3、代码实现

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        stack<int> s;
        int index=0;
        //先将数据压入栈中直到栈顶元素等于popV的第一个元素
        for(int i=0;i<pushV.size();i++){
            s.push(pushV[i]);
            while(!s.empty()&&s.top()==popV[index]){
                s.pop();
                index++;
            }
           

        }
        return s.empty();
        
    }
};

滑动窗口的最大值

题目来源:牛客网

1、问题描述

描述
给定一个长度为 n 的数组 nums 和滑动窗口的大小 size ,找出所有滑动窗口里数值的最大值。

例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

数据范围: 1 \le size \le n \le 100001≤size≤n≤10000,数组中每个元素的值满足 |val| \le 10000∣val∣≤10000
要求:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)

2、思路解析

滑动窗口+双端队列
利用双端队列记录当前滑动窗口的元素索引
队头记录滑动窗口中最大元素的索引
队列中存放的元素索引对应的是递减的,就是说队头元素就是区间内最大的元素,队列中元素索引对应元素是递减的
遍历数组:

  • 如果队列最左侧索引已不在滑动窗口范围内,弹出队列最左侧索引
  • 通过循环确保队列的最左侧索引所对应元素值最大
  • 新元素入队
  • 从第一个滑动窗口的末尾索引开始将最大值存储到结果v中

先形成大小为k的窗口

3、代码实现

class Solution {
public:
    vector<int> maxInWindows(const vector<int>& nums, int size) {
        vector<int> v;
        deque<int> q;
        int begin=0;
        int end=1;
        q.push_back(begin);
        for(;end<=nums.size();end++){
            //先取大小的size的窗口
            if(end-begin+1>size){
                //队头元素是窗口内最大元素
                v.push_back(nums[q.front()]);
          
                begin++;
            }
            //判断队头元素是不是在数据范围内------控制数据在窗口内部----在窗口内部寻找最大值
            while(!q.empty()&&q.front()<begin){
                q.pop_front();
            }
            //队尾元素小于新来元素就是直接删除-----控制队列中元素有序---将小于新来元素删除达到元素递增
            while(!q.empty()&&nums[q.back()]<nums[end]){
                q.pop_back();
                
            }
            //新来元素入对
            q.push_back(end);
            
            
        }
        return v;
        
    }
};
  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

自首的小偷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值