刷题(2)栈,队列(2)-题目

目录

1.用两个栈实现队列(剑指offer 9 ) 

2.包含min函数的栈(剑指offer 30 ) 

3.栈的压入弹出顺序(剑指offer 31)(重要) 

4.滑动窗口的最大值(剑指offer 59 ) (重要)


1.用两个栈实现队列(剑指offer 9 ) 

题目描述:

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

解题思路:

栈是先入后出,而队列是先入先出,
维护两个栈,一个push栈,一个pop栈.
入队操作: 无脑压入push栈

出队操作:假如pop栈非空,直接弹栈顶元素完事
          假如pop空,而就把push栈依次弹出,并且压入stack2,最后弹个pop的栈顶。
          假如两个栈都空,就啥事不干。

代码:

class Solution
{
public:
    void push(int node) {
        stack1.push(node);
    }

    int pop() {
		if(stack1.empty() && stack2.empty())
			return -1;
		
        int res;
        if(stack2.empty()){
            while(!stack1.empty()){
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
		res = stack2.top();
		stack2.pop();
		return res;
    }

private:
    stack<int> stack1;
    stack<int> stack2;
};

相关:两个队列实现栈

跟上一题的解法不一样

  • 任何时候两个队列总有一个是空的。
  • 添加元素总是向非空队列中 add 元素。
  • 取出元素的时候总是将非空的那个队列,所有元素除队尾最后一个元素外,依次导入另一空队列中,最后一个元素出队,返回。

2.包含min函数的栈(剑指offer 30 ) 

题目描述:

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

解题思路:

两个栈,一个正常栈,一个min栈
压入:
压a的时候,正常栈直接压a,而压入min栈的时候,跟min栈顶b比较一下,假如a小于b,压a,假如a大于等于b,压b (min栈空的时候,直接压)
弹栈:
两个栈都正常弹
返回min,直接返回min的栈顶

代码:

class Solution {
public:
    void push(int value) {
        s1.push(value);
        if(minstack.empty())
            minstack.push(value);
        else if(value <= minstack.top())
            minstack.push(value);
        else
            minstack.push(minstack.top());
    }
    void pop() {
        s1.pop();
        minstack.pop();
    }
    int top() {
        return s1.top();
    }
    int min() {
        return minstack.top();
    }
private:
    stack<int> s1;
    stack<int> minstack;
};

3.栈的压入弹出顺序(剑指offer 31)(重要) 

题目描述:

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

解题思路:

建立一个辅助栈,按压栈顺序压栈,按出栈顺序出栈
具体办法:

1) 外层遍历入栈顺序: 假如当前栈顶和当前被比较的出栈数字一样,那就出栈,直到不一样为止。否则继续入栈。(感觉这个符合我的思维,能想到)

2) 外层遍历出栈顺序:  用i遍历出栈顺序(for循环),如果下一个要出栈的数字,在辅助栈s1顶则,直接出栈,i前进一位,即进入下一个循环,如果辅助栈为空或者不在,则按压栈顺序压一个,并重新判断,重复这个过程,如果压栈顺序里面所有数字都压进去了,还没有找到下一个弹出的数字,则不可能是出栈顺序。

代码:

class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        if (pushed.size() != popped.size())
            return false;
        if (pushed.empty())
            return true;
        stack<int> stk;

        int j = 0; // 当前被比较的poped 下标
        for (int num: pushed) // 模拟压栈出栈的过程
        {
            stk.push(num);
            // 当前栈顶和出栈的数值 一样, 那就出栈,直到不一样为止
            while (stk.size() && j < popped.size() &&  stk.top() == popped[j]) 
            {
                stk.pop();
                j++;
            }
        }

        return stk.empty();
    }
};



class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
	
        if(pushV.size() != popV.size())
			return false;
	   stack<int> s1;
       int index =0;
       for(int i=0;i<popV.size();++i){
           //如果下一个要弹出的数字 popV[i] 不在栈s1顶,那么按压栈顺序pushV[index++]压栈,直到popV[i] 压进去
           //过程中 检查 pushV都压进去了,那就不是一个弹出顺序 
            while(s1.empty() || s1.top() != popV[i]){  
                if(index >=pushV.size())
                    return false;
                s1.push(pushV[index++]);
            }
           s1.pop();
       }
       return s1.empty(); 
    }
};

4.滑动窗口的最大值(剑指offer 59 ) (重要)

题目描述:

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。

假如数组长度为n,窗口大小为w,则一共产生n-w+1个窗口的最大值。

解题思路:

中心思想: 如果我比你大,我来了,你就得滚。用双端队列deque 放下标 or 放pair也行 下标+值 维持一个从大到小的结构
队列头永远是最大的。

deque放下标,输入数组是arr,依次遍历arr,deque每次执行加数和减数操作。
假设现在遍历到arr[i]

加数:
1)deque为空,直接把下标i放进deque
2)deque不为空,取出deque队尾放的下标j,arr【j】跟arr【i】比较,假如,arr【i】<=arr【j】,把i放进去,假如小于,deque把j给弹出来,新队尾继续跟arr[i]比较,直到遇到比arr[i]大或者deque为空,那把i加进来

其实就是            

while(!qmax.empty() && num[i]>num[qmax.back()]){
                qmax.pop_back();
            }

减数逻辑:
假如deque队头的值是x, i-x+1>w,说明这个下标已经过期了,弹出来(因为新窗口最右端是i,窗口大小是w)

先加逻辑 再减逻辑

代码:

class Solution {
public:
    vector<int> maxInWindows(const vector<int>& num, unsigned int size)
    {
        int len= num.size();
		vector<int> res;
		if(len == 0 || size ==0 )
			return res;
		// 假如size比num要大
       /* if(size>= len){
			int m = num[0];
			for(int i=0;i!=len;++i){
				m = max(m,num[i]);
			}
			res.push_back(m);
			return res;
		} */
		
		if(size>len){  // 我寻思铁子也没说清 当窗口比数组大的时候咋变啊
			return res;
		}
		
		//存的是下标
		deque<int> qmax;
		
		for(int i=0;i!=len;++i){
			//如果当前值比队列的最尾部值num[q.back()]大,那么删除队列尾部,保证最大值在队列首部
			while(!qmax.empty() && num[i]>num[qmax.back()]){
				qmax.pop_back();
			}
			
			qmax.push_back(i); //加入新数
			
			if(i-qmax.front()+1>size){
				qmax.pop_front(); //如果最大值超过了size的区间(i-qmax.front()+1),那么就把最大值删除
			}
			if(i>=size-1){
				res.push_back(num[qmax.front()]); //存放数值
			}
		}
		return res;
	}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值