文章详解
(1)递归
主要思路:
递归按照深度遍历,为了保证同一层节点
放入同一个切片
,递归时记录每个节点的深度depth
,递归到新节点将值追加到对应depth
的切片中
func levelOrder(root *TreeNode) [][]int {
res := [][]int{}
depth := 0
var help func(root *TreeNode, depth int)
help = func(root *TreeNode, depth int) {
if root == nil {
return
}
if len(res) == depth {
res = append(res, []int{})
}
res[depth] = append(res[depth], root.Val)
help(root.Left, depth + 1)
help(root.Right, depth + 1)
}
help(root, depth)
return res
}
(2)层序遍历
主要思路:
借助辅助队列【先进先出】:切片实现
根元素先入队
队列不为空时,遍历节点,并进行下一次迭代【节点左、右子树推入队列】
func levelOrder(root *TreeNode) [][]int {
res := [][]int{}
if root == nil {
return res
}
curQueue := []*TreeNode{root}
for len(curQueue) > 0 {
vals := []int{}
nextQueue := []*TreeNode{}
for _, node := range curQueue {
vals = append(vals, node.Val)
if node.Left != nil {
nextQueue = append(nextQueue, node.Left)
}
if node.Right != nil {
nextQueue = append(nextQueue, node.Right)
}
}
res = append(res, vals)
curQueue = nextQueue
}
return res
}
文章详解
主要思路:
与二叉树遍历一样,交换左右孩子节点,翻转左子树和右子树
注意:中序翻转,会导致左子树翻转两次,因此需要之后翻转回来
(1)递归
//前序
func invertTree(root *TreeNode) *TreeNode {
if root == nil {
return root
}
root.Left, root.Right = root.Right, root.Left
invertTree(root.Left)
invertTree(root.Right)
return root
}
//后序
func invertTree(root *TreeNode) *TreeNode {
if root == nil {
return root
}
invertTree(root.Left)
invertTree(root.Right)
root.Left, root.Right = root.Right, root.Left
return root
}
//中序
func invertTree(root *TreeNode) *TreeNode {
if root == nil {
return root
}
invertTree(root.Left)
root.Left, root.Right = root.Right, root.Left
invertTree(root.Left)
return root
}
(2)迭代
//前序
func invertTree(root *TreeNode) *TreeNode {
node := root
stack := []*TreeNode{}
for len(stack) > 0 || node != nil {
for node != nil {
node.Left, node.Right = node.Right, node.Left
stack = append(stack, node)
node = node.Left
}
node = stack[len(stack) - 1]
stack = stack[:len(stack) - 1]
node = node.Right
}
return root
}
//后序
func invertTree(root *TreeNode) *TreeNode {
node := root
stack := []*TreeNode{}
for len(stack) > 0 || node != nil {
for node != nil {
node.Left, node.Right = node.Right, node.Left
stack = append(stack, node)
node = node.Right
}
node = stack[len(stack) - 1]
stack = stack[:len(stack) - 1]
node = node.Left
}
return root
}
//中序
func invertTree(root *TreeNode) *TreeNode {
node := root
stack := []*TreeNode{}
for len(stack) > 0 || node != nil {
for node != nil {
stack = append(stack, node)
node = node.Left
}
node = stack[len(stack) - 1]
node.Left, node.Right = node.Right, node.Left
stack = stack[:len(stack) - 1]
node = node.Left
}
return root
}
(3)层序
func invertTree(root *TreeNode) *TreeNode {
if root == nil {
return root
}
node := root
queue := []*TreeNode{node}
for len(queue) > 0 {
for _, node := range queue {
node = queue[0]
queue = queue[1:]
node.Left, node.Right = node.Right, node.Left
if node.Left != nil {
queue = append(queue, node.Left)
}
if node.Right != nil {
queue = append(queue, node.Right)
}
}
}
return root
}
文章详解
主要思路:比较左右子树是否为对称结构
1)如果当前节点的左子树和右子树都为空,返回真
2)若当前节点左子树或右子树一个为空,一个不为空,或者当前节点的左右孩子值不相等,返回false
3)递归传入当前节点左右孩子外侧节点
及左右孩子内侧节点
(1)递归
func isSymmetric(root *TreeNode) bool {
if root == nil {
return true
}
return help(root.Left, root.Right)
}
func help(left, right *TreeNode) bool {
if left == nil && right == nil {
return true
}
if left == nil || right == nil || left.Val != right.Val {
return false
}
return help(left.Left, right.Right) && help(left.Right, right.Left)
}
(2)迭代
func isSymmetric(root *TreeNode) bool {
if root == nil {
return true
}
queue := []*TreeNode{}
queue = append(queue, root.Left, root.Right)
for len(queue) > 0 {
left := queue[0]
right := queue[1]
queue = queue[2:]
if left == nil && right == nil {
continue
}
if left == nil || right == nil || left.Val != right.Val {
return false
}
queue = append(queue, left.Left, right.Right, left.Right, right.Left)
}
return true
}
107.二叉树的层次遍历II
199.二叉树的右视图
637.二叉树的层平均值
429.N叉树的层序遍历
515.在每个树行中找最大值
116.填充每个节点的下一个右侧节点指针
117.填充每个节点的下一个右侧节点指针II
任何一个节点都来到自己3次。
前序:第1次来到自己处理;中序:第2次来到自己处理;后序:第3次来到自己处理;
fun dfs(root *TreeNode) {
if root == nil {
return
}
// 1.第一次到该节点
dfs(root.Left)
// 2.遍历完左子树回到该节点
dfs(root.Right)
// 3.遍历完右子树回到该节点
}
前序遍历:任何一棵子树都满足中—>左—>右
顺序。即对任何一个节点,先处理自己,之后遍历左子树、右子树。中、后序类似。
主要思路:
把头结点先压入栈
栈不为空时,每次弹出一个节点,先压右,再压左,得到中—>左—>右
中序迭代思路:
(1)一直寻找子树左边界,并压入栈,直到遇到空节点
(2)栈弹出节点,进行操作,弹出节点的右子树重复步骤(1)
(3)没有子树,且栈为空
跟着大佬学习效率还是高的,递归、迭代方法基本理解!