剑指Offer 队列&栈题目集合

用两个栈实现队列

刷题链接
https://www.nowcoder.com/practice/54275ddae22f475981afa2244dd448c6

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

思路一
使用两个栈来实现队列的功能。栈 1 用于存储入队的元素,而栈 2 用于存储出队的元素。
1.push方法将元素压入栈 1。
2.pop方法首先检查栈 2 是否为空。如果为空,则将栈 1 中的所有元素移到栈 2。然后,弹出栈 2 中的顶部元素并返回。

在这里插入图片描述

复杂度分析

时间复杂度:在最坏情况下,pop 操作的时间复杂度是 O(n),但在平均情况下,当栈2中有元素时,pop 操作的时间复杂度是 O(1)。这是因为在平均情况下,元素不会每次都从栈1移动到栈2。总体而言,这个实现的 push 操作是 O(1),而 pop 操作的最坏情况下是 O(n),平均情况下是 O(1)。
空间复杂度: O(n),辅助栈的空间,最差的情况下两个栈共存储N个元素。

python3

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []

    def push(self, x: int) -> None:
        # 入队时直接将元素压入 stack1
        self.stack1.append(x)

    def pop(self) -> int:
        # 如果 stack2 为空,将 stack1 中的元素依次弹出并压入 stack2,实现队列的先进先出
        if not self.stack2:
            while self.stack1:
                self.stack2.append(self.stack1.pop())
        # 弹出 stack2 的栈顶元素,即队列头部的元素
        return self.stack2.pop()

C++

class Solution {
  public:
    // 入队操作,将元素压入 stack1
    void push(int x) {
        stack1.push(x);
    }

    // 出队操作,实现队列的先进先出
    int pop() {
        // 如果 stack2 为空,将 stack1 中的元素依次弹出并压入 stack2
        if (stack2.empty()) {
            while (!stack1.empty()) {
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        // 弹出 stack2 的栈顶元素,即队列头部的元素
        int frontElement = stack2.top();
        stack2.pop();
        return frontElement;
    }

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

包含min函数的栈

刷题链接
https://www.nowcoder.com/practice/4c776177d2c04c2494f2555c9fcc1e49

题目描述

在这里插入图片描述

思路一
使用两个栈,一个用于存储元素,另一个用于存储当前栈中的最小元素。在 push 操作中,如果新元素小于等于辅助栈中的最小元素,则将其也压入辅助栈。在 pop 操作中,如果弹出的元素等于辅助栈中的最小元素,则也弹出辅助栈中的最小元素。top 和 min 函数分别返回主栈和辅助栈的栈顶元素。

复杂度分析

时间复杂度:O(1),所有操作的时间复杂度都是 O(1),因此整个代码的时间复杂度为 O(1)
空间复杂度: O(n),使用了两个栈,即 stack 和 min_stack,用于存储元素和维护最小元素。每个栈的空间复杂度为 O(n),其中 n 是栈中元素的个数。

python3

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        # 主栈,用于存储元素
        self.stack = []
        # 辅助栈,用于存储当前栈中的最小元素
        self.min_stack = []

    def push(self, x: int) -> None:
        # 将元素压入主栈
        self.stack.append(x)
        # 更新辅助栈,存储当前栈中的最小元素
        if not self.min_stack or x <= self.min_stack[-1]:
            self.min_stack.append(x)

    def pop(self) -> None:
        # 弹出主栈的栈顶元素
        if self.stack:
            popped_element = self.stack.pop()
            # 如果弹出的元素是当前栈中的最小元素,则同时更新辅助栈
            if popped_element == self.min_stack[-1]:
                self.min_stack.pop()

    def top(self):
        # 返回主栈的栈顶元素
        if self.stack:
            return self.stack[-1]
    def min(self):
        # 返回当前栈中的最小元素
        if self.min_stack:
            return self.min_stack[-1]

C++

class Solution {
public:
    void push(int value) {
        stack.push(value);
        if (min_stack.empty() || value <= min_stack.top()) {
            min_stack.push(value);
        }
    }

    void pop() {
        if (!stack.empty()) {
            int popped_element = stack.top();
            stack.pop();
            if (popped_element == min_stack.top()) {
                min_stack.pop();
            }
        }
    }

    int top() {
        if (!stack.empty()) {
            return stack.top();
        }
        return -1;
    }

    int min() {
        if (!min_stack.empty()) {
            return min_stack.top();
        }
        return -1;
    }
private:
    std::stack<int> stack;
    std::stack<int> min_stack;
};

栈的压入、弹出序列

刷题链接
https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106

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

思路一
使用一个辅助栈,遍历压栈序列,并在每次压入一个元素后检查是否需要弹出栈顶元素,直到弹出序列的当前元素与栈顶元素不相同时停止。最后,如果栈为空,说明给定的弹出序列是可能的;否则,不可能。

复杂度分析

时间复杂度:O(n),最坏情况下需要遍历两个数组各一次;
空间复杂度:O(n),辅助栈空间最大为一个数组的长度;

python3

class Solution:
    def IsPopOrder(self, pushV: List[int], popV: List[int]) -> bool:
        if not pushV or not popV:
            return False

        stack = []  # 辅助栈,用于模拟压入和弹出操作
        idx = 0  # 弹出序列的索引
        for num in pushV:
            stack.append(num)  # 将当前元素压入栈
            # 循环检查栈顶元素是否需要弹出
            while stack and stack[-1] == popV[idx]:
                stack.pop()  # 弹出栈顶元素
                idx += 1  # 移动到下一个弹出元素
        # 如果栈为空,说明给定的弹出序列是可能的;否则,不可能
        return not stack

C++

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pushV int整型vector 
     * @param popV int整型vector 
     * @return bool布尔型
     */
    bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
        if (pushV.empty() || popV.empty()) {
            return false;
        }

        stack<int> stk;  // 辅助栈,用于模拟压入和弹出操作
        int idx = 0;  // 弹出序列的索引
        for (int num : pushV) {
            stk.push(num);  // 将当前元素压入栈
            // 循环检查栈顶元素是否需要弹出
            while (!stk.empty() && stk.top() == popV[idx]) {
                stk.pop();  // 弹出栈顶元素
                idx++;  // 移动到下一个弹出元素
            }
        }
        // 如果栈为空,说明给定的弹出序列是可能的;否则,不可能
        return stk.empty();
    }
};

翻转单词序列

刷题链接
https://www.nowcoder.com/practice/3194a4f4cf814f63919d0790578d51f3

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

思路一
直接法:将字符串按空格进行切分,然后进行逆序拼接。

复杂度分析

时间复杂度:O(n),只需对列表进行一次切分,再按要求进行拼接;
空间复杂度:O(n),单词列表占用线性大小的额外空间;

python3

class Solution:
    def ReverseSentence(self , str: str) -> str:
        # 将字符串按空格分割为单词列表
        words = str.split()
        # 逆序遍历单词列表并拼接成新的字符串
        reversed_str = ""
        for i in range(len(words) - 1, -1, -1):
            reversed_str += words[i]
            if i > 0:
                reversed_str += " "  # 在单词之间添加空格
        return reversed_str

C++

class Solution {
public:
    string ReverseSentence(string str) {
        string result;
        // 使用字符串流按空格分割原句子
        stringstream ss(str);
        string word;
        // 从流中读取单词并逆序拼接到结果字符串中
        while (ss >> word) {
            if (!result.empty()) {
                result = word + " " + result;
            } else {
                result = word;
            }
        }
        return result;
    }
};

滑动窗口的最大值

刷题链接
https://www.nowcoder.com/practice/1624bc35a45c42c0bc17d17fa0cba788

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

思路一
暴力法:直接遍历两层:第一层为窗口起点,第二层为窗口长度,即遍历了所有的窗口的每个位置。

复杂度分析

时间复杂度:O(n*m),双层for循环,n为数组长度,m为窗口长度;
空间复杂度:O(n),结果res占用线性大小的空间;

python3

class Solution:
    def maxInWindows(self , num: List[int], size: int) -> List[int]:
        n = len(num)
        if not num or size <= 0 or size > n:
            return []

        res = []
        for i in range(n-size+1):
            tmp = max(num[i:i+size])
            res.append(tmp)
        return res

C++

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param num int整型vector 
     * @param size int整型 
     * @return int整型vector
     */
    vector<int> maxInWindows(vector<int>& num, int size) {
        int n = num.size();
        vector<int> res;

        if (num.empty() || size <= 0 || size > n) {
            return res;
        }

        for (int i = 0; i <= n - size; ++i) {
            int tmp = *max_element(num.begin() + i, num.begin() + i + size);
            res.push_back(tmp);
        }
        return res;
    }
};
  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AI小笔记

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

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

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

打赏作者

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

抵扣说明:

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

余额充值