剑指offer 队列&栈

本文探讨如何利用栈实现队列操作,包括用两个栈实现队列的push和pop,保持O(1)的时间复杂度。同时介绍带有min函数的栈设计,以及判断栈的压入和弹出序列的可能性。此外,还讨论了滑动窗口最大值问题的单调队列解决方案,确保在O(n)的时间复杂度内找到所有滑动窗口的最大值。
摘要由CSDN通过智能技术生成

三、队列&栈

JZ9 用两个栈实现队列

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

push直接放入stack1,stack1用于存储数据。
pop 若stack2中有数据,直接pop,否则把stack1中的所有数据放入stack2,返回最上面的数。

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

    int pop() {
        int result = 0;
        if(stack2.empty()){
            while(!stack1.empty()){
               int tmp = stack1.top();
               stack1.pop();
               stack2.push(tmp);
           }
        }
        result = stack2.top();
        stack2.pop();
        return result;
    }

private:
    stack<int> stack1;
    stack<int> stack2;
};
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def push(self, node):
        self.stack1.append(node)
        # write code here
    def pop(self):
        if len(self.stack2)==0:
            while len(self.stack1):
                tmp = self.stack1[len(self.stack1)-1]
                self.stack1.remove(tmp)
                self.stack2.append(tmp)
        result = self.stack2[len(self.stack2)-1]
        self.stack2.remove(result)
        return result

JZ30 包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数,输入操作时保证 pop、top 和 min 函数操作时,栈中一定有元素。
此栈包含的方法有:
push(value):将value压入栈中
pop():弹出栈顶元素
top():获取栈顶元素
min():获取栈中最小元素

数据范围:操作数量满足0≤n≤300 ,输入的元素满足∣val∣≤10000
进阶:栈的各个操作的时间复杂度是 O(1) ,空间复杂度是 O(n)

借助辅助栈,他记录每进来node之后的最小值,pop的时候stack和辅助栈都需pop。

class Solution {
public:
    stack<int> stack1, minstack;
    void push(int value) {
        stack1.push(value);
        if(minstack.empty())
            minstack.push(value);
        else{
            int tmp = minstack.top();
            if(value<tmp)
                minstack.push(value);
            else
                minstack.push(tmp);
        }
    }
    void pop() {
        stack1.pop();
        minstack.pop();
    }
    int top() {
        return stack1.top();
    }
    int min() {
        return minstack.top();
    }
};
class Solution:
    def __init__(self):
        self.minc = []
        self.stack = []
    def push(self, node):
        self.stack.append(node)
        if len(self.minc) == 0:
            self.minc.append(node)
        else:
            tmp = self.minc[len(self.minc)-1]
            if node < tmp:
                self.minc.append(node)
            else:
                self.minc.append(tmp)
    def pop(self):
        result = self.stack[len(self.stack)-1]
        self.stack.remove(result)
        self.minc.remove(self.minc[len(self.minc)-1])
    def top(self):
        return self.stack[len(self.stack)-1]
    def min(self):
        return self.minc[len(self.minc)-1]

JZ31 栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列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 的所有数字均不相同

借助辅助栈,如果pushV[i] != popV[j],把pushV[i]压入辅助栈。若相等则i,j均后移,并判断辅助栈顶元素和popV[j]是否相等,相等继续弹出,直到i<pushV.size()。

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        stack<int> tmp;
        int i=0, j=0;
        while(i<pushV.size()){
            if(pushV[i] != popV[j]){
                tmp.push(pushV[i]);
                i++;
            }
            else{
                i++;
                j++;
                while(!tmp.empty() && tmp.top()==popV[j]){
                    tmp.pop();
                    j++;
                }
            }
        }
        return tmp.empty();
    }
};
class Solution:
    def __init__(self):
        self.stack = []
    def IsPopOrder(self , pushV: List[int], popV: List[int]) -> bool:
        i = 0
        j = 0
        while i < len(pushV):
            if pushV[i] != popV[j]:
                self.stack.append(pushV[i])
                i += 1
            else:
                i += 1
                j += 1
                while len(self.stack) and self.stack[len(self.stack)-1] == popV[j]:
                    j += 1
                    self.stack.remove(self.stack[len(self.stack)-1])
        return len(self.stack)==0

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“nowcoder. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a nowcoder.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

数据范围:1≤n≤100
进阶:空间复杂度 O(n),时间复杂度O(n),保证没有只包含空格的字符串。

class Solution {
public:
    string ReverseSentence(string str) {
        string reverse;
        stack<string> re;
        string tmp = "";
        int loc = 0;
        for(int i = 0; i < str.length(); i++){
            if(str[i] == ' '){
                loc = i;
                re.push(tmp);
                tmp = "";
                continue;
            }
            tmp += str[i];
        }
        if(loc == 0)
            re.push(str.substr(loc, str.size()));
        else
            re.push(str.substr(loc+1, str.size()));
        while(!re.empty()){
            reverse += re.top() + ' ';
            re.pop();
        }
        return reverse.substr(0, reverse.size()-1);
    }
};
class Solution:
    def ReverseSentence(self , str: str) -> str:
        split = str.split(' ')
        print(split)
        reverse = ''
        for i in range(len(split)-1, -1, -1):
            reverse += split[i] + ' '
        print(reverse)
        return reverse[:-1]

JZ59 滑动窗口的最大值(困难)

给定一个长度为 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≤size≤n≤10000,数组中每个元素的值满足∣val∣≤10000
要求:空间复杂度 O(n),时间复杂度 O(n)

我们要维护size大小的队列, 当进来一个比队尾元素要大的数时,要把队尾元素删除,他不可能成为后面的最大值;若对头的值超出滑动窗口,也要删除队头元素;队头元素一直为最大的,这个队列是个单调队列

class Solution {
public:
    vector<int> maxInWindows(const vector<int>& nums, int size) {
        deque<int> q; // 存储的是元素位置信息
        vector<int> result;
        for(int i = 0; i< nums.size();i++){
            // 队尾元素比新来的小,就会被替代
            while(!q.empty() && nums[q.back()] < nums[i])
                q.pop_back();
            // 加入新来的元素位置
            q.push_back(i);
            // 如果队头的元素出窗口了,那么需要移除
            if(q.front() < i-size+1){
                q.pop_front();
            }
            // 大于窗口的才放入结果
            if(i >= size-1){
                result.push_back(nums[q.front()]);
            }
        }
        return result;
    }
};
class Solution:
    def maxInWindows(self , num: List[int], size: int) -> List[int]:
        stack = []
        dequeue = []
        for i in range(len(num)):
            while len(dequeue) and num[dequeue[len(dequeue)-1]] < num[i]:
                dequeue.remove(dequeue[len(dequeue)-1])
            dequeue.append(i)
            if dequeue[0] < i-size+1:
                dequeue.remove(dequeue[0])
            if i >= size-1:
                stack.append(num[dequeue[0]])
        return stack
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值