「这是我参与11月更文挑战的第 10 天,活动详情查看:2021最后一次更文挑战」
刷算法题,从来不是为了记题,而是练习把实际的问题抽象成具体的数据结构或算法模型,然后利用对应的数据结构或算法模型来进行解题。个人觉得,带着这种思维刷题,不仅能解决面试问题,也能更多的学会在日常工作中思考,如何将实际的场景抽象成相应的算法模型,从而提高代码的质量和性能
按之字形顺序打印二叉树
题目来源:LeetCode - 剑指 Offer 32 - III. 从上到下打印二叉树 III
题目描述
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推
例如:
给定二叉树:
[3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[20,9],
[15,7]
]
示例
示例 1
输入:{1,2,3,#,#,4,5}
返回值:[[1],[3,2],[4,5]]
说明:如题面解释,第一层是根节点,从左到右打印结果,第二层从右到左,第三层从左到右。
示例 2
输入:{8,6,10,5,7,9,11}
返回值:[[8],[10,6],[5,7,9,11]]
示例 3
输入:{1,2,3,4,5}
返回值:[[1],[3,2],[4,5]]
解题
解法一:双端队列
思路
我最开始想这个题的时候,其实是用的栈+队列,奇数层入栈、偶数层入队列,然后取结点的时候,先取右节点,再取左节点,发现这样做,到第4层的时候就不对了
然后就想到双端队列,因为有了前边那种思路,很容易想到用双端队列,用双端队列,这道题就简单了
首先需要借助两个队列
- queue:如果queue中的结点是偶数层的,首先将队列中的元素,顺序放入到结果集res中,然后逆序访问queue中的元素,将每个元素的子节点,按照先右节点后左节点的顺序,将子节点放入到临时队列tmpQueue中。如果是奇数层,首先将队列中的元素,顺序放入到结果集res中,然后逆序访问queue中的元素,将每个元素的子节点,按照先左节点后右节点的顺序,将子节点放入到临时队列tmpQueue中
- tmpQueue:用于临时存储每一层的结点
文字比较抽象,看图
level = 0(偶数层)
- 先顺序遍历queue中的元素,将其放入结果集res
- 逆序取出queue中的元素,按照先右子树后左子树的顺序,将下一层的节点放入tmpQueue中
- 将tmpQueue赋值给queue
level = 1(奇数层)
- 先顺序遍历queue中的元素,将其放入结果集res
- 逆序取出queue中的元素,按照先左子树后右子树的顺序,将下一层的节点放入tmpQueue中
- 将tmpQueue赋值给queue
level = 2(偶数层)
- 先顺序遍历queue中的元素,将其放入结果集res
- 逆序取出queue中的元素,按照先右子树后左子树的顺序,将下一层的节点放入tmpQueue中
- 将tmpQueue赋值给queue
level = 3(奇数层)
代码
var res [][]int
if root == nil {
return res
}
queue := []*TreeNode{root}
level := 0
for len(queue) != 0 {
tmpQueue := []*TreeNode{}
res = append(res, []int{})
for _, node := range queue {
res[level] = append(res[level], node.Val)
}
if level % 2 == 0 {
for i:=len(queue)-1; i >= 0; i-- {
if queue[i].Right != nil {
tmpQueue = append(tmpQueue, queue[i].Right)
}
if queue[i].Left != nil {
tmpQueue = append(tmpQueue, queue[i].Left)
}
}
} else {
for i:=len(queue)-1; i >= 0; i-- {
if queue[i].Left != nil {
tmpQueue = append(tmpQueue, queue[i].Left)
}
if queue[i].Right != nil {
tmpQueue = append(tmpQueue, queue[i].Right)
}
}
}
queue = tmpQueue
level++
}
return res