算法与数据结构学习之路三:算法与数据结构的融合应用 -- 栈与队列


栈与队列问题

   栈是数据结构的基础,也是解决问题的重要方法。
💗 STL中的栈与队列
   在STL中,stack表示栈,Queue表示队列。
   (1).stack
   stack是通过序列容器来实现的。stack主要有以下几个特点:
   ① stack严格遵循后进先出(LIFO)原则,因此stack不提供元素的任何迭代器操作,不会向外部提供可用的前向或后向迭代器类型。
   ② stack只能通过top从栈顶获取和删除数据,不能遍历,不支持随机存储。
   ③ stack的常用操作:

使用时注意包含头文件 #include <stack>
s.empty()	//如果栈为空返回true,否则返回false  
s.size()	//返回栈中元素的个数  
s.pop()	//删除栈顶元素但不返回其值  
s.top()	//返回栈顶的元素,但不删除该元素  
s.push(X)	//在栈顶压入新元素 ,参数X为要压入的元素

   (2).queue
   queue是通过序列容器来实现的。queue主要有以下几个特点:
   ① queue遵循先入先出(FIFO)原则,queue不提供元素的任何迭代器操作,不会向外部提供可用的前向或后向迭代器类型。
   ② queue只能从一端插入,另一端删除,不能遍历,不支持随机存储。
   ③ queue的常用操作:

使用时注意包含头文件 #include <queue>
q.empty()// 如果队列为空返回true,否则返回false  
q.size() // 返回队列中元素的个数  
q.pop()  //删除队列首元素但不返回其值  
q.front()  // 返回队首元素的值,但不删除该元素  
q.push(X) //在队尾压入新元素 ,X为要压入的元素
q.back() //返回队列尾元素的值,但不删除该元素  
1. 数据栈与辅助栈解决问题

   数据栈和辅助栈就是利用两个栈,其中一个栈来存放数据,另一个栈用来计算另一些数据(栈的最大值,最小值等)。通过牺牲空间来换取时间。
🐟 ① 155. 最小栈==========================================================================================
   设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈
    push(x) – 将元素 x 推入栈中。 pop() – 删除栈顶的元素。 top() – 获取栈顶元素。getMin() – 检索栈中的最小元素。

输入输出解释
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.

   思路:此题要求要在常数时间内检索到最小元素的栈,因此,无法通过入栈后在判断最小元素的方式,因此,需要添加辅助栈。辅助栈用来存放每次遇到更小的元素,这样就能保证在辅助栈中的元素是当前栈中最小的元素。

class MinStack {
public:
    stack<int> s;
    stack<int> minStack;
    /** initialize your data structure here. */
    MinStack() {

    }    
    void push(int x) {
        s.push(x);    //数据栈入栈
        if(minStack.empty() || x<=minStack.top())   //如果辅助栈为空或当前值小于辅助栈栈顶元素,则入辅助栈。
            minStack.push(x);
    }
    
    void pop() {
        if(s.top()==minStack.top())  //如果数据栈的栈顶元素与辅助栈的栈顶元素相同时,
        					    	//则同时将栈顶元素出栈,否则只对数据栈出栈
            minStack.pop();
        s.pop();
    }
    int top() {
        return s.top();
    }
    int getMin() {   //辅助栈的栈顶元素即为当前栈中的最小元素。
        return minStack.top();  
    }
};
2. 队列与栈的转换(相互实现)

   此类问题通常包括用队列来实现栈或用栈来实现队列。
🐟 ① 225. 用队列实现栈=====================================================================================
   使用队列实现栈的下列操作:
   push(x) – 元素 x 入栈     pop() – 移除栈顶元素   top() – 获取栈顶元素   empty() – 返回栈是否为空

   思路:用队列实现栈有三种方式:
   (1).利用二个队列,压入(push)时间复杂度为O(1),弹出(pop)时间复杂度为O(n).。
      压入(push):直接将数据放入到队列q1当中。

在这里插入图片描述

      弹出(pop):添加一个临时队列 q2,将 q1队列的前 n-1个数据,入队到 q2中,然后弹出 q1的最后一个元素。再将 q1q2交换。
在这里插入图片描述

class MyStack {
public:
    /** Initialize your data structure here. */
    queue<int> que;
    queue<int> helper;  //临时辅助队列
    int temp;
    MyStack() {

    }
    /** Push element x onto stack. */
    void push(int x) {
        que.push(x);     //压入(push)直接将数据入队q1
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        while(que.size()>1){      //将q1队列中前n-1个数据,入队到q2中
            int temp=que.front();
            helper.push(temp);
            que.pop();
        }
        int ans=que.front();  
        que.pop();	 //弹出q1的最后一个元素
        queue<int> temp=helper;
        helper=que;
        que=temp;   //将q1与q2交换
        return ans;
        
    }
    /** Get the top element. */
    int top() {
        while(que.size()>1){
            temp=que.front();
            helper.push(temp);
            que.pop();
        }
        int ans=que.front();
        helper.push(ans);
        que.pop();
        queue<int> temp=helper;
        helper=que;
        que=temp;
        return ans;
    }   
};

   (2).利用二个队列,压入(push)时间复杂度为O(n),弹出(pop)时间复杂度为O(1).。
      压入(push):让每一个新元素从 q2 入队,同时把这个元素作为栈顶元素保存。当 q1 非空(也就是栈非空),我们让 q1 中所有的元素全部出队,再将出队的元素从 q2 入队。通过这样的方式,新元素(栈中的栈顶元素)将会在 q2 的前端。我们通过将 q1q2 互相交换的方式来避免把 q2 中的元素往 q1 中拷贝。

在这里插入图片描述
      弹出(pop):直接将数据从队列 q1当中弹出即可。
在这里插入图片描述

class MyStack {
public:
    /** Initialize your data structure here. */
    queue<int> que;
    queue<int> helper;
    int temp;
    MyStack() {

    }  
    /** Push element x onto stack. */
    void push(int x) {
        helper.push(x);
        while(!que.empty()){   //当 `q1` 非空(也就是栈非空),我们让 `q1` 中所有的元素全部出队,再将出队的元素从 `q2` 入队。
            int temp=que.front();
            helper.push(temp);
            que.pop();
        }
        queue<int> temp_q=helper;
        helper=que;
        que=temp_q;
    }
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int ans=que.front();   //直接从q1中出队
        que.pop();
        return ans;   
    }
    /** Get the top element. */
    int top() {
        int ans=que.front();
        return ans;
    }  
};

   (3).利用一个队列,压入(push)时间复杂度为O(n),弹出(pop)时间复杂度为O(1).。
      压入(push):每当入队一个新元素的时候,我们可以把队列的顺序反转过来。

在这里插入图片描述
      弹出(pop):直接将数据从队列 q1当中弹出即可。
在这里插入图片描述

class MyStack {
public:
    /** Initialize your data structure here. */
    queue<int> que;
    queue<int> helper;
    int temp;
    MyStack() {

    }
    /** Push element x onto stack. */
    void push(int x) {
        que.push(x);
        int len=que.size();
        while(len>1){   
            int temp=que.front();   //每当入队一个新元素的时候,我们可以把队列的顺序反转过来
            que.push(temp);
            que.pop();
            len--;
        }
    }
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int ans=que.front();
        que.pop();
        return ans;
        
    }
    /** Get the top element. */
    int top() {
        int ans=que.front();
        return ans;
    }
};
3. 单调栈

   所谓单调栈,就是栈中存放的数据是有序的,单调栈分为单调递增栈单调递减栈注意:这里说的递增递减指的是出栈的顺序,而不是在栈中数据的顺序。
   ① 单调递增栈:数据出栈的顺序是单调递增序列。
   ② 单调递减栈:数据出栈的顺序是单调递减序列。

在这里插入图片描述

🐟 ① 496. 下一个更大元素 I==================================================================================
   给定两个没有重复元素的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。
   nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出-1。

输入输出解释
nums1 = [4,1,2],
nums2 = [1,3,4,2]
[-1,3,-1]对于num1中的数字4,你无法在第二个数组中找到下一个更大的数字,因此输出 -1。
对于num1中的数字1,第二个数组中数字1右边的下一个较大数字是 3。
对于num1中的数字2,第二个数组中没有下一个更大的数字,因此输出 -1。

   思路:利用单调栈,依次单调递增(出栈单调递减)的求取更大的元素,然后利用unordered_map存储对应元素与下一个更大元素。若当前元素cur大于栈顶(当前元素pre),则将(key,value)=(pre,cur)存入map,并出栈。将当前元素入栈。


在这里插入图片描述

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        vector<int> ans;
        if(nums1.size()>nums2.size() || nums2.size()<=0){
            return ans;
        }
        stack<int> s;
        unordered_map<int,int> m;
        s.push(nums2[0]);   /将第一个元素入栈
        for(int i=1;i<nums2.size();i++){
            while(!s.empty()){
                if(nums2[i]>s.top()){  如果当前元素cur大于栈顶元素,则说明上一个元素pre的下一个最大元素为cur,则将(key,value)=(pre,cur)存入map
                    m[s.top()]=nums2[i];
                    s.pop();  //将当前栈顶清空,出栈过程,出栈元素数值递减
                }else
                    break;    
            }
            s.push(nums2[i]);  //将当前元素cur入栈
        }
        while(!s.empty()){  //栈中其余元素是没有下一个更大元素的值
            m[s.top()]=-1;
            s.pop();
        }
        for(int i=0;i<nums1.size();i++){  //在子集nums1中遍历,查找对应map中的下一更大元素,放入vector中。
            ans.push_back(m[nums1[i]]);
        }

        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值