今日内容:
● 层序遍历 10
● 226.翻转二叉树
● 101.对称二叉树 2
1. 层序遍历
关联 leetcode
102.二叉树的层序遍历
107.二叉树的层次遍历II 199.二叉树的右视图 637.二叉树的层平均值 429.N叉树的层序遍历 515.在每个树行中找最大值 116.填充每个节点的下一个右侧节点指针 117.填充每个节点的下一个右侧节点指针II 104.二叉树的最大深度 111.二叉树的最小深度
- 相当于图论的广度优先搜索
- 按照层序来输出当前层的所有元素
- 二叉树本身这个结构无法做到层序遍历
- 需要借助额外数据结构:队列
- 存储每一层遍历过的元素
- 需要借助额外数据结构:队列
- 题解
- 102.二叉树的层序遍历
-
个人解法:
-
两个数组:当前层节点数组+子节点数组
type TreeNode struct { Val int Left *TreeNode Right *TreeNode } / func levelOrder(root *TreeNode) [][]int { rets := make([][]int, 0)// 最终结果 if root == nil { return rets } curNodes := make([]*TreeNode, 0)//当前层节点 curNodes = append(curNodes, root)//初始化放入root节点 sonNodes := make([]*TreeNode, 0)//当前层节点的子节点 ret := make([]int, 0)//存储当前节点值的数组 LeverLoop: for _, node := range curNodes {//遍历当前层所有节点 ret = append(ret, node.Val)//按序存储当前层节点值 //添加当前节点的非空子节点【左右有序】 if node.Left != nil { sonNodes = append(sonNodes, node.Left) } if node.Right != nil { sonNodes = append(sonNodes, node.Right) } } rets = append(rets, ret)//存储当前层节点值 if len(sonNodes) != 0 {//当前层还有子节点存在 curNodes = sonNodes//继续遍历子节点层 sonNodes = make([]*TreeNode, 0)//初始化子节点 ret = make([]int, 0)//初始化当前层节点值 goto LeverLoop//继续循环遍历 } return rets } /*不用 goto*/ func levelOrder(root *TreeNode) [][]int { rets := make([][]int, 0) if root == nil { return rets } curNodes := make([]*TreeNode, 0) curNodes = append(curNodes, root) for len(curNodes) > 0 { ret := make([]int, 0) sonNodes := make([]*TreeNode, 0) for _, node := range curNodes { ret = append(ret, node.Val) if node.Left != nil { sonNodes = append(sonNodes, node.Left) } if node.Right != nil { sonNodes = append(sonNodes, node.Right) } } rets = append(rets, ret) curNodes = sonNodes } return rets }
-
-
卡哥讲解解法:
-
一个数组实现
func levelOrder(root *TreeNode) [][]int { rets := [][]int{} if root == nil { //防止为空 return rets } //用链表实现队列, 队尾进, 队首出 queue := list.New() queue.PushBack(root) ret := make([]int, 0) for queue.Len() > 0 { length := queue.Len() //保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数) for i := 0; i < length; i++ { node := queue.Remove(queue.Front()).(*TreeNode) //出队列 if node.Left != nil { queue.PushBack(node.Left) } if node.Right != nil { queue.PushBack(node.Right) } ret = append(ret, node.Val) //将值加入本层切片中 } rets = append(rets, ret) //放入结果集 ret = []int{} //清空层的数据 } return rets }
-
-
- 102.二叉树的层序遍历
2. 翻转二叉树 (优先掌握递归)
关联 leetcode 226.翻转二叉树
- 左右翻转的是节点本身【即是指针而不简单是交换数值】
- 有个个人思路:
- 用上一道的广度搜索【把空指针一期加进去】,然后遍历结果数值,分配左右孩子
- 这道用 递归前序、后序最直接
- 确定返回值
- 确定终止条件
- 处理逻辑
- 题解【递归遍历二叉树】
-
前序:中左右
func invertTree(root *TreeNode) *TreeNode { if root == nil { return root } node := root //前序遍历: 中左右 //每次都交换当前节点的左右节点 node.Right, node.Left = node.Left, node.Right invertTree(node.Left) invertTree(node.Right) return root }
-
后序:左右中
func invertTree(root *TreeNode) *TreeNode { if root == nil { return root } node := root //后序遍历: 左右中 //每次都交换当前节点的左右节点 invertTree(node.Left) invertTree(node.Right) node.Right, node.Left = node.Left, node.Right return root }
-
3. 对称二叉树(优先掌握递归)
关联 leetcode 101. 对称二叉树
- 递归只能使用后序
- 后序:左右中
- 解题思路:
- 收集左右孩子节点 —返回—> 上一个节点
- 比较:
- 左右孩子的外侧节点
- 左孩子的左节点,右孩子的右节点
- 左右孩子的内侧节点
- 左孩子的右节点,右孩子的左节点
- 左右孩子的外侧节点
- 题解
-
递归法
type TreeNode struct { Val int Left *TreeNode Right *TreeNode } func compare(left, right *TreeNode) bool { /*比较两个节点自身*/ if left == nil && right != nil { return false } if right == nil && left != nil { return false } if right == nil && left == nil { return true } // left != nil && right != nil // 需要比较节点的数值了 if left.Val != right.Val { return false } // 比较左右节点的外侧节点,内侧节点 outRes := compare(left.Left, right.Right) insideRes := compare(left.Right, right.Left) return insideRes && outRes } func isSymmetric(root *TreeNode) bool { if root == nil { return true } return compare(root.Left, root.Right) }
-
迭代法
- 自己构造一个栈
- 待比较的节点两两一组,互相配对
-