[剑指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.
提示:
- 各函数的调用总次数不超过 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 之前弹出。
提示:
0 <= pushed.length == popped.length <= 1000
0 <= pushed[i], popped[i] < 1000
pushed
是popped
的排列。
解法:
直接开个辅助栈试一试。同时建立一个指针,初始指向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;
}
};