[剑指Offer]30~33

[剑指Offer]30~33

学习使用工具

剑指Offer http://itmyhome.com/sword-means-offer/sword-means-offer.pdf

LeetCode的剑指Offer题库 https://leetcode.cn/problemset/all/

剑指 Offer 30. 包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.min();   --> 返回 -2.

提示:

  1. 各函数的调用总次数不超过 20000 次

解法:

看到这题的时候我在想,不会要用栈去实现栈吧,结果真的……额外开一个辅助栈用于保存最小值,并解决pop掉最小值时如何追溯上一个最小值的问题。

class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []
        self.minstack = []

    def push(self, x: int) -> None:
        self.stack.append(x)
        if not self.minstack or x <= self.minstack[-1]:
            self.minstack.append(x)

    def pop(self) -> None:
        if self.stack.pop() == self.minstack[-1]:
            self.minstack.pop()

    def top(self) -> int:
        return self.stack[-1]

    def min(self) -> int:
        return self.minstack[-1]

剑指 Offer 31. 栈的压入、弹出序列

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

示例 1:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1

示例 2:

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。

提示:

  1. 0 <= pushed.length == popped.length <= 1000
  2. 0 <= pushed[i], popped[i] < 1000
  3. pushedpopped 的排列。

解法:

直接开个辅助栈试一试。同时建立一个指针,初始指向popped列表的开头。

  • 对pushed进行遍历,每遍历一个元素时,将这个元素加入辅助栈。
  • 每加入一个元素时,进行循环判定:如果此时辅助栈栈顶值等于popped指针位置值,则辅助栈出栈,指针后移一位;如果不等于或者此时辅助栈已经出空,则结束循环。
  • 当pushed的所有元素已经遍历完时,判断指针是否遍历完popped列表。如果已经遍历完,则返回True,否则返回False。
def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
        stack = []
        j = 0
        for i in pushed:
            stack.append(i)
            while stack and stack[-1] == popped[j]:
                stack.pop()
                j += 1

        if j == len(popped):
            return True

        return False

剑指 Offer 32 - I. 从上到下打印二叉树

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回:

[3,9,20,15,7]

提示:

节点总数 <= 1000

解法:

经典层序遍历,使用一个队列和一个双端队列来实现。

  • 初始化,树的根节点从双端队列右端入列,结果队列为空。
  • 从双端队列左侧出列一个结点,将此节点值加入结果队列,随后,将刚刚出列节点的左右节点(若不为空)从右端入列双端队列。循环,直到双端队列为空。
def levelOrder(self, root: TreeNode) -> List[int]:
        if not root:
            return []
        
        queue = collections.deque()
        res = []

        queue.append(root)
        while queue:
            node = queue.popleft()
            res.append(node.val)
            if node.left:
                queue.append(node.left)
            if node.right:
                queue.append(node.right)

        return res

剑指 Offer 32 - II. 从上到下打印二叉树 II

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]

提示:

节点总数 <= 1000

解法:

先自己摸索着在上一题基础上改出来了

  • 添加一个队列lres用于记录每层的节点
  • 添加变量num和flag共同控制每层的节点数量
  • 添加temp作为当层的节点计数
def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root:
            return []
        
        queue = collections.deque()
        res = []
        lres = []
        num = 1
        temp = num
        flag = 0

        queue.append(root)
        while queue:
            node = queue.popleft()
            lres.append(node.val)
            if node.left:
                queue.append(node.left)
            else: flag += 1
            if node.right:
                queue.append(node.right)
            else: flag += 1
            
            temp -= 1
            if temp <= 0 :
                res.append(lres)
                lres = []
                num *= 2
                num -= flag
                temp = num
                flag = 0

        return res

思路优化:直接在队列里插入空指针作为标记,取到空指针就认为当前层遍历结束。

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        if (root) {
            queue<TreeNode*> q;
            q.push(root); q.push(nullptr);
            res.emplace_back(vector<int> ());
            while (!q.empty()) {
                TreeNode *p = q.front(); q.pop();
                if (p) {
                    res.back().emplace_back(p -> val);
                    if (p -> left) q.push(p -> left);
                    if (p -> right) q.push(p -> right);
                } else if (!q.empty()) {
                    res.emplace_back(vector<int> ());
                    q.push(nullptr);
                }
            }
        }
        return res;
    }
};
posted @ 2023-03-06 14:25  无机呱子  阅读(9)  评论(0编辑  收藏  举报