代码随想录算法训练营|day15

第六章 二叉树

  • 102.二叉树的层序遍历
  • 226.翻转二叉树
  • 101.对称二叉树
  • 相关推荐
  • 学习补充
  • 总结

102.二叉树的层序遍历

文章详解
(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
}

226.翻转二叉树

文章详解

主要思路:
与二叉树遍历一样,交换左右孩子节点,翻转左子树和右子树
注意:中序翻转,会导致左子树翻转两次,因此需要之后翻转回来

(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
}   

101.对称二叉树

文章详解

主要思路:比较左右子树是否为对称结构
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)没有子树,且栈为空

总结

跟着大佬学习效率还是高的,递归、迭代方法基本理解!

你可能感兴趣的:(代码随想录练习,算法,go)