代码随想录:二叉树

基础篇

前序遍历

144. 二叉树的前序遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree1.Right = tree2
    tree2.Left = tree3
    r := preorderTraversal(tree1)
    fmt.Println(r) // [1 2 3]
}
func preorderTraversal(root *TreeNode) []int {
    // ......
}

【拓展】如何 不使用递归 来完成二叉树的前序遍历呢?

答案

思路:

对二叉树进行递归遍历,需要从以下 3 个方面入手:

1.递归终止条件:root结点为nil

2.本轮递归需要做的事情:先遍历中,再遍历左,最后遍历右

3.返回值:无

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 前序遍历函数
func preorderTraversal(root *TreeNode) []int {
    var result []int
    traversal(root, &result) // 为了让traversal函数中对result的append操作同步到本函数中,这里需要传切片的地址
    return result
}
func traversal(node *TreeNode, result *[]int) {
    if node == nil { // 确定递归的出口
       return
    }
    // 先将当前节点的值加入结果列表
    *result = append(*result, node.Val)
    // 然后递归遍历左子树
    traversal(node.Left, result)
    // 最后递归遍历右子树
    traversal(node.Right, result)
}

非递归实现:

思路:我们可以使用栈来完成这一操作,先将 root 结点入栈,然后一个循环(循环条件为栈不为空)

当栈不为空的时候,把栈中元素弹出,放入到目标数组result中,然后将右结点和左结点依次放入栈中。

由于先序遍历是 中左右 的顺序,而栈是 先入后出,所以入栈是需要先将右结点入栈,然后将左结点入栈。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func preorderTraversal(root *TreeNode) []int {
    stack := make(map[int]*TreeNode) // map模拟栈
    result := make([]int, 0)
    stack[0] = root
    for len(stack) != 0 {
       topNode := stack[len(stack)-1]
       delete(stack, len(stack)-1)
       if topNode != nil {
          result = append(result, topNode.Val)
       } else {
          continue
       }
       stack[len(stack)] = topNode.Right
       stack[len(stack)] = topNode.Left
    }
    return result
}

中序遍历

94. 二叉树的中序遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree1.Right = tree2
    tree2.Left = tree3
    r := inorderTraversal(tree1)
    fmt.Println(r) // [1 3 2]
}
func inorderTraversal(root *TreeNode) []int {
    // ......
}
答案
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func inorderTraversal(root *TreeNode) []int {
    result := make([]int, 0)
    traversal(root, &result) // 这里要传地址
    return result
}

// 中序遍历:左中右
func traversal(root *TreeNode, result *[]int) {
    if root == nil {
       return
    }
    traversal(root.Left, result)
    *result = append(*result, root.Val)
    traversal(root.Right, result)
}

后序遍历

145. 二叉树的后序遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree1.Right = tree2
    tree2.Left = tree3
    r := postorderTraversal(tree1)
    fmt.Println(r) // [3 2 1]
}
func postorderTraversal(root *TreeNode) []int {
    // ......
}
答案
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func postorderTraversal(root *TreeNode) []int {
    result := make([]int, 0)
    traversal(root, &result) // 这里要传地址
    return result
}

// 后序遍历:左右中
func traversal(root *TreeNode, result *[]int) {
    if root == nil {
       return
    }
    traversal(root.Left, result)
    traversal(root.Right, result)
    *result = append(*result, root.Val)
}

层序遍历

102. 二叉树的层序遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree4 := &TreeNode{4, nil, nil}
    tree5 := &TreeNode{5, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := levelOrder(tree1)
    fmt.Println(r) // [[1] [2 3] [4 5]]
}
func levelOrder(root *TreeNode) [][]int {
    // ......
}
答案
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
func levelOrder(root *TreeNode) [][]int {
    if root == nil {
       return nil
    }
    queue := make([]*TreeNode, 1)
    layerItem := make([]int, 0)
    result := make([][]int, 0)
    queue[0] = root
    for len(queue) != 0 {
       size := len(queue) // 记录每层的元素个数
       layerItem = []int{}
       for size > 0 {
          layerItem = append(layerItem, queue[0].Val) // 将队首元素加入到layerItem中
          if queue[0].Left != nil {
             queue = append(queue, queue[0].Left)
          }
          if queue[0].Right != nil {
             queue = append(queue, queue[0].Right)
          }
          queue = queue[1:] // 去掉队首元素
          size--
       }
       result = append(result, layerItem)
    }
    return result
}

二叉树的右视图

199. 二叉树的右视图

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree4 := &TreeNode{4, nil, nil}
    tree5 := &TreeNode{5, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := rightSideView(tree1)
    fmt.Println(r) // [1, 3, 5]
}
func rightSideView(root *TreeNode) []int {
    // ......
}
答案

思路:将每一层的最后一个元素添加到 result 数组中。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func rightSideView(root *TreeNode) []int {
    if root == nil {
       return nil
    }
    result := make([]int, 0)
    queue := make([]*TreeNode, 1)
    queue[0] = root
    for len(queue) != 0 {
       size := len(queue)
       for size > 0 {
          if size == 1 {
             result = append(result, queue[0].Val) // 将每层最后一个元素加入到result
          }
          if queue[0].Left != nil {
             queue = append(queue, queue[0].Left)
          }
          if queue[0].Right != nil {
             queue = append(queue, queue[0].Right)
          }
          queue = queue[1:] // 弹出队首元素
          size--
       }
    }
    return result
}

N叉树的层序遍历

429. N 叉树的层序遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
type Node struct {
    Val      int
    Children []*Node
}
func main() {
    node1 := &Node{1, nil}
    node2 := &Node{2, nil}
    node3 := &Node{3, nil}
    node4 := &Node{4, nil}
    node5 := &Node{5, nil}
    node6 := &Node{6, nil}
    node1.Children = []*Node{node2, node3, node4}
    node2.Children = []*Node{node5, node6}
    r := levelOrder(node1)
    fmt.Println(r) // [[1] [2 3 4] [5 6]]
}
func levelOrder(root *Node) [][]int {
    // ......
}
答案

定义size,统计每层元素的个数。

将root加入到队列中,当队列不为空时,取出队列的首元素,放到layerItem中

将首元素的所有孩子结点加入队列。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func levelOrder(root *Node) [][]int {
    if root == nil {
       return nil
    }
    queue := make([]*Node, 1)
    result := make([][]int, 0)
    layerItem := make([]int, 0)
    queue[0] = root
    for len(queue) != 0 {
       layerItem = []int{}
       size := len(queue)
       for size > 0 {
          layerItem = append(layerItem, queue[0].Val)
          if queue[0].Children != nil {
             queue = append(queue, queue[0].Children...)
          }
          queue = queue[1:]
          size--
       }
       result = append(result, layerItem)
    }
    return result
}

二叉树的最大深度

104. 二叉树的最大深度

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree4 := &TreeNode{4, nil, nil}
    tree5 := &TreeNode{5, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := maxDepth(tree1)
    fmt.Println(r) // 3
}
func maxDepth(root *TreeNode) int {
    // ......
}
答案

递归,先找左子树的深度,然后找有子树的深度,最后求最大值

1
2
3
4
5
6
func maxDepth(root *TreeNode) int {
    if root == nil {
       return 0
    }
    return max(maxDepth(root.Left), maxDepth(root.Right)) + 1
}

二叉树的最小深度

111. 二叉树的最小深度

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree4 := &TreeNode{4, nil, nil}
    tree5 := &TreeNode{5, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := minDepth(tree1)
    fmt.Println(r) // 2
}
func minDepth(root *TreeNode) int {
    // ......
}
答案
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func minDepth(root *TreeNode) int {
	if root == nil {
		return 0
	}
	left := minDepth(root.Left)
	right := minDepth(root.Right)
	if left == 0 || right == 0 {  // 注意处理单边二叉树的问题
		return max(left, right) + 1
	}
	return min(left, right) + 1
}

翻转二叉树

226. 翻转二叉树

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func invertTree(root *TreeNode) *TreeNode {
	//......
}
func main() {
	//      4
	//     / \
	//    2   7
	//   / \ / \
	//  1  3 6  9
	root := &TreeNode{Val: 4}
	root.Left = &TreeNode{Val: 2}
	root.Right = &TreeNode{Val: 7}
	root.Left.Left = &TreeNode{Val: 1}
	root.Left.Right = &TreeNode{Val: 3}
	root.Right.Left = &TreeNode{Val: 6}
	root.Right.Right = &TreeNode{Val: 9}
	// 翻转树
	invertedRoot := invertTree(root)
	// 层序打印翻转后的树
	fmt.Println(invertedRoot.Val, "\n",
		invertedRoot.Left.Val, invertedRoot.Right.Val, "\n",
		invertedRoot.Left.Left.Val, invertedRoot.Left.Right.Val,
		invertedRoot.Right.Left.Val, invertedRoot.Right.Right.Val)
	// 4
	// 7 2
	// 9 6 3 1
}
答案

将二叉树左子树和右子树进行交换。

1
2
3
4
5
6
7
8
9
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
}

对称二叉树

101. 对称二叉树

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{2, nil, nil}
    tree4 := &TreeNode{3, nil, nil}
    tree5 := &TreeNode{4, nil, nil}
    tree6 := &TreeNode{4, nil, nil}
    tree7 := &TreeNode{3, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree2.Left = tree4
    tree2.Right = tree5
    tree3.Left = tree6
    tree3.Right = tree7
    r := isSymmetric(tree1)
    fmt.Println(r) // true
}
func isSymmetric(root *TreeNode) bool {
    // ......
}
答案

思路:

先明确本题只能使用后序遍历,因为我们需要搜集左右孩子的信息,进行比较。

现在需要确定递归的3个条件:递归的结束条件、本次递归需要做的事情,本次递归的返回值。

递归的结束条件:也就是这里可以直接得出结果的条件,具体如下:

  1. 左空,右非空—-false
  2. 右空,左非空—-false
  3. 左空,右空—-true
  4. 左非空,右非空,但值不相等—-false

剩下的一个条件就是左右不为空,且值相等的情况,这就是我们继续向下一层递归的条件。

下一层递归的条件(也就是本次递归需要做的事情)

如果 左结点的右孩子==右结点的左孩子,且左结点的左孩子==右结点的右孩子,那么继续往下一层进行比较。

本次递归的返回值:左右结点是否相等(这里的相等指的是是否对称)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func isSymmetric(root *TreeNode) bool {
    if root == nil {
       return true
    }
    return compare(root.Left, root.Right)
}
func compare(left, right *TreeNode) bool {
    if left == nil && right != nil { // 把判空条件写在前面,防止后面出现空指针异常
       return false
    } else if left != nil && right == nil {
       return false
    } else if left == nil && right == nil {
       return true
    } else if left.Val != right.Val { // 这里left不可能为空指针
       return false
    } else { // 左右都不为空的情况,应该递归调用compare函数,比较左右孩子是否对称
       // 左结点的左孩子 vs 右结点的右孩子 && 左结点的右孩子 vs 右结点的左孩子
       return compare(left.Left, right.Right) && compare(left.Right, right.Left)
    }
}

完全二叉树的节点个数

222. 完全二叉树的节点个数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree4 := &TreeNode{4, nil, nil}
    tree5 := &TreeNode{5, nil, nil}
    tree6 := &TreeNode{6, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree2.Left = tree4
    tree2.Right = tree5
    tree3.Left = tree6
    r := countNodes(tree1)
    fmt.Println(r) // 6
}

func countNodes(root *TreeNode) int {
    // ......
}
答案

方法1: 遍历所有结点(这里采用后序遍历)

1
2
3
4
5
6
func countNodes(root *TreeNode) int {
    if root == nil {
       return 0
    }
    return countNodes(root.Left) + countNodes(root.Right) + 1
}

方法2: 利用完全二叉树的性质:如果右结点不为空,那么左结点也一定不为空。

我们可以判断某子二叉树是否是满二叉树,如果是满二叉树,那我们可以根据二叉树的深度直接计算出该二叉树的节点数量。

即:nodeCount=2^depth-1

如何判断是否为满二叉树呢?一个指针一直向左遍历,另一个指针一直向右遍历,如果左指针的深度等于右指针的深度,说明该二叉树为满二叉树。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func countNodes(root *TreeNode) int {
    if root == nil {
       return 0
    }
    left := root.Left
    right := root.Right
    leftDepth := 0
    rightDepth := 0
    for left != nil {
       left = left.Left
       leftDepth++
    }
    for right != nil {
       right = right.Right
       rightDepth++
    }
    if leftDepth == rightDepth { // 是满二叉树
       return 2<<leftDepth - 1 // 使用左移来实现乘方的效果
    }
    return countNodes(root.Left) + countNodes(root.Right) + 1
}

平衡二叉树

110. 平衡二叉树

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{2, nil, nil}
    tree4 := &TreeNode{3, nil, nil}
    tree5 := &TreeNode{4, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := isBalanced(tree1)
    fmt.Println(r) // true
}
func isBalanced(root *TreeNode) bool {
    // ......
}
答案

使用后序遍历,先计算左结点的“深度”,再计算右结点的“深度”,然后计算左右结点的深度差是否大于1。

这里的深度指的是最深结点的层数(从1开始),但如果左右结点的深度超过1了,我们直接用返回-1(用-1来向上层标识是否合法,如果不合法我们直接就返回false了,不需要再对左右的深度差进行判断)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
func isBalanced(root *TreeNode) bool {
    if root == nil {
       return true
    }
    if treeDepth(root.Left) == -1 || treeDepth(root.Right) == -1 { // 注意这里添加这个条件
       return false
    }
    if math.Abs(float64(treeDepth(root.Left)-treeDepth(root.Right))) > 1 {
       return false
    }
    return true
}

func treeDepth(root *TreeNode) int {
    if root == nil {
       return 0
    }
    lDepth := treeDepth(root.Left)
    if lDepth == -1 {
       return -1
    }
    rDepth := treeDepth(root.Right)
    if rDepth == -1 {
       return -1
    }
    if math.Abs(float64(lDepth-rDepth)) > 1 {
       return -1
    } else {
       return max(lDepth, rDepth) + 1
    }
}

二叉树的所有路径

257. 二叉树的所有路径

本题较为复杂,可以多加练习。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree4 := &TreeNode{4, nil, nil}
    tree5 := &TreeNode{5, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := binaryTreePaths(tree1)
    fmt.Println(r) // [1->2 1->3->4 1->3->5]
}
func binaryTreePaths(root *TreeNode) []string {
    // ......
}
答案

本题使用前序遍历(深度优先),当某条分支遍历完之后,在向上进行回溯。如下图:

二叉树的所有路径.png

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func binaryTreePaths(root *TreeNode) []string {
    res := make([]string, 0)
    var travel func(node *TreeNode, s string)
    travel = func(node *TreeNode, s string) {
       if node.Left == nil && node.Right == nil { // 递归出口:node为叶子结点
          v := s + strconv.Itoa(node.Val) // 叶子结点的值也需要加上,而且后面不加"->"
          res = append(res, v)
          return // 遇到叶子结点时,需要进行回溯,直接向上层递归返回
       }
       // 这里是前序遍历(深度优先遍历),中右左
       s = s + strconv.Itoa(node.Val) + "->" // s表示当前已经遍历过的路径
       if node.Left != nil {                 // 左结点不为空,继续遍历左结点
          travel(node.Left, s) // 递归遍历node的左孩子
       }
       if node.Right != nil { // 右结点不为空,继续遍历右结点
          travel(node.Right, s)
       }
    }
    travel(root, "") //
    return res
}

左叶子之和

404. 左叶子之和

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree4 := &TreeNode{4, nil, nil}
    tree5 := &TreeNode{5, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := sumOfLeftLeaves(tree1)
    fmt.Println(r) // 6
}

func sumOfLeftLeaves(root *TreeNode) int {
    // ......
}
答案

递归实现,采用后序遍历的方式(左右中)。

确定递归的出口:node 为空,或者 root 的左右孩子为空。

本轮递归需要做的事情:获取 node 左孩子的 sum,获取右孩子的 sum,将二者求和。

递归的返回值:sum。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func sumOfLeftLeaves(root *TreeNode) int {
    if root == nil {
       return 0
    }
    // 只递归到非叶子结点(因为非叶子节点才能确定它的左孩子)
    // 我们无法通过某个几点判断它是左孩子还是右孩子,所以递归到叶子结点也没有意义
    if root.Left == nil && root.Right == nil {
       return 0
    }
    lSum := sumOfLeftLeaves(root.Left)
    rSum := sumOfLeftLeaves(root.Right)
    if root.Left != nil && root.Left.Left == nil && root.Left.Right == nil {
       lSum = root.Left.Val // 这里只是记录目标值,不做任何返回,以实现下次递归的复用
    }
    return lSum + rSum
}

找树左下角的值

513. 找树左下角的值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree4 := &TreeNode{4, nil, nil}
    tree5 := &TreeNode{5, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := findBottomLeftValue(tree1)
    fmt.Println(r) // 4
}
func findBottomLeftValue(root *TreeNode) int {
    // ......
}
答案
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func findBottomLeftValue(root *TreeNode) int {
    maxDepth := -1
    target := 0
    var traversal = func(node *TreeNode, depth int) {}
    traversal = func(node *TreeNode, depth int) {
       if node.Left == nil && node.Right == nil {
          if depth > maxDepth {
             maxDepth = depth
             target = node.Val
          }
       }
       if node.Left != nil {
          traversal(node.Left, depth+1)
          // 这里将回溯的过程隐藏在了第二个参数里面
          // 也就是往后递归一层的时候,depth加1了,但这个加1操作只对下层的递归有效,
          // 当回溯到本层的时候,depth值是不变的
       }
       if node.Right != nil {
          traversal(node.Right, depth+1)
       }
    }
    traversal(root, 1)
    return target
}

进阶篇

路径总和

112. 路径总和

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree4 := &TreeNode{4, nil, nil}
    tree5 := &TreeNode{5, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := hasPathSum(tree1, 8)
    fmt.Println(r) // true
}
func hasPathSum(root *TreeNode, targetSum int) bool {
    // ......
}
答案

本题和二叉树的所有路径差不多,也是使用前序遍历,即:中左右。

确定递归的出口:node 的左右结点都为空(node 为叶子结点)

确定本次递归需要做的事情:如果 node 的左结点不为空,遍历左结点,如果 node 的右结点不为空,遍历右结点

递归的返回值:是否满足条件的布尔值

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
func hasPathSum(root *TreeNode, targetSum int) bool {
    if root == nil {
       return false
    }
    var traversal func(node *TreeNode, sum int) bool
    traversal = func(node *TreeNode, sum int) bool {
       if node.Left == nil && node.Right == nil {
          if targetSum == sum+node.Val {
             return true // 向上层返回true
          }
       }
       sum += node.Val
       if node.Left != nil {
          // 当某层递归返回true时,直接向上层返回true,否则不做返回,继续递归
          // 注意:这不能直接写成 return traversal(node.Left, sum)
          if traversal(node.Left, sum) {
             return true
          }
       }
       if node.Right != nil {
          if traversal(node.Right, sum) {
             return true
          }
       }
       return false
    }
    return traversal(root, 0)
}

从中序与后序遍历序列构造二叉树

本题较为复杂,暂时跳过。

106. 从中序与后序遍历序列构造二叉树

最大二叉树

654. 最大二叉树

1
2
3
4
5
6
7
8
func main() {
	nums := []int{3, 2, 1, 6, 0, 5}
	r := constructMaximumBinaryTree(nums)
	fmt.Println(r)
}
func constructMaximumBinaryTree(nums []int) *TreeNode {
	// ......
}
答案

构造二叉树,我们都需要使用前序遍历。

确定递归的出口:nums 只有1个元素,直接返回用该元素构造的结点。

确定本次递归需要做的事情:先找出最大值和最大值所在的下标,用最大值将原数组进行分隔,对左右数组分别调用 constructMaximumBinaryTree(区间需要统一为左闭右开)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func constructMaximumBinaryTree(nums []int) *TreeNode {
    if nums == nil {
       return nil
    }
    if len(nums) == 1 {
       return &TreeNode{nums[0], nil, nil}
    }
    maxVal := nums[0]
    maxIndex := 0
    for i := 1; i < len(nums); i++ {
       if nums[i] > maxVal {
          maxVal = nums[i]
          maxIndex = i
       }
    }
    curNode := &TreeNode{maxVal, nil, nil} // 中
    if maxIndex > 0 {
       curNode.Left = constructMaximumBinaryTree(nums[0:maxIndex]) // 左闭右开区间
    }
    if maxIndex < len(nums)-1 {
       curNode.Right = constructMaximumBinaryTree(nums[maxIndex+1:])
    }
    return curNode
}

合并二叉树

617. 合并二叉树

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func main() {
	node11 := &TreeNode{1, nil, nil}
	node12 := &TreeNode{2, nil, nil}
	node13 := &TreeNode{3, nil, nil}
	node21 := &TreeNode{4, nil, nil}
	node22 := &TreeNode{5, nil, nil}
	node23 := &TreeNode{6, nil, nil}
	node11.Left = node12
	node11.Right = node13
	node21.Left = node22
	node21.Right = node23
	r := mergeTrees(node11, node21)
	fmt.Println(r)  // &{5 0xc000008060 0xc000008078}
}
func mergeTrees(root1 *TreeNode, root2 *TreeNode) *TreeNode {
    // ......
}
答案
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
func mergeTrees(root1 *TreeNode, root2 *TreeNode) *TreeNode {
    // 构造二叉树我们都使用前序遍历(中左右)
    // 递归出口
    if root1 == nil { // 这里也包含了root1和root2同时为空的情况,返回nil
       return root2
    }
    if root2 == nil {
       return root1
    }
    root1.Val = root1.Val + root2.Val // 把两个二叉树合并到root1上
    root1.Left = mergeTrees(root1.Left, root2.Left)
    root1.Right = mergeTrees(root1.Right, root2.Right)
    return root1
}

二叉搜索树中的搜索

700. 二叉搜索树中的搜索

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{4, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{7, nil, nil}
    tree4 := &TreeNode{1, nil, nil}
    tree5 := &TreeNode{3, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree2.Left = tree4
    tree2.Right = tree5
    r := searchBST(tree1, 3)
    fmt.Println(r)
}
func searchBST(root *TreeNode, val int) *TreeNode {
    // ......
}
答案

方法1:递归法

先确定递归的出口:如果 root 的值等于了 val 则返回 root,如果 root 为空,则返回 root(空)

如果 val 大于 root 的值,则向右子树搜索,否则向左子树搜索。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func searchBST1(root *TreeNode, val int) *TreeNode {
    if root == nil || root.Val == val {
       return root
    }
    var result *TreeNode
    if val > root.Val {
       result = searchBST1(root.Right, val)
    } else {
       result = searchBST1(root.Left, val)
    }
    return result
}

方法2:迭代法

当 root 不为空时,一直往下搜索,最后返回 root。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func searchBST2(root *TreeNode, val int) *TreeNode {
    for root != nil {
       if val == root.Val {
          return root
       }
       if val > root.Val { // 往右搜索
          root = root.Right
       } else {
          root = root.Left
       }
    }
    return root
}

验证二叉搜索树

98. 验证二叉搜索树

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{5, nil, nil}
    tree2 := &TreeNode{4, nil, nil}
    tree3 := &TreeNode{6, nil, nil}
    tree4 := &TreeNode{3, nil, nil}
    tree5 := &TreeNode{7, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := isValidBST(tree1)
    fmt.Println(r) // false
}
func isValidBST(root *TreeNode) bool {
	// ......
}
答案

思路1:我们可能会这样想,采用后序遍历,先分别判断左右子树是否是平衡二叉树(左右子树为空返回true),如果是的话,再分四种情况进行讨论:

  • 如果左右都为空,返回 true;
  • 如果左右都不为空,同时左右中元素依次递增的话,返回 true;
  • 如果左不为空(右为空),同时左大于中,返回 true;
  • 如果右不为空(左为空),同时右大于中,返回 true;

但是这样存在一个漏洞,那就是如果 root 的右孩子(right)大于 root,但 right(right 是二叉搜索树)的左孩子小于了 root,会判定 true 而不是 false,如:root = [ 5 ,4, 6, null, null, 3, 7 ]。

所以,思路1是行不通的。


观察发现,如果 root 是二叉搜索树,那么中序遍历得到的数组一定是升序的。

思路2:直接中序遍历,如果得到的数组是升序的,则返回 true。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
func isValidBST1(root *TreeNode) bool {
    result := make([]int, 0)
    var traversal func(node *TreeNode, result *[]int)
    traversal = func(node *TreeNode, result *[]int) {
       if node == nil {
          return
       }
       traversal(node.Left, result)
       *result = append(*result, node.Val)
       traversal(node.Right, result)
    }
    traversal(root, &result)
    for i := 1; i < len(result); i++ {
       if result[i] <= result[i-1] { // 注意,这里等于也要返回false
          return false
       }
    }
    return true
}

但这样需要额外开辟数组空间。

思路3:在思路 2 的基础上进行改进,不需要额外的数组空间,在遍历时维护一个 maxVal,如果当前数值大于 maxVal,则更新 maxVal,否则返回 false。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func isValidBST2(root *TreeNode) bool {
    // 由于Leetcode上面不允许定义全局变量(容易遇到不可知的错误),所以这里只能定义为局部变量,然后再定义一层函数调用
    var maxVal = math.MinInt64 // 记录遍历过的最大的数值
    var traversal func(root *TreeNode) bool
    traversal = func(root *TreeNode) bool {
       if root == nil {
          return true
       }
       var lValid, rValid bool
       lValid = traversal(root.Left) // 左
       if root.Val > maxVal {        // 中
          maxVal = root.Val
       } else {
          return false
       }
       rValid = traversal(root.Right) // 右
       return lValid && rValid
    }
    return traversal(root)
}

二叉搜索树的最小绝对差

530. 二叉搜索树的最小绝对差

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{5, nil, nil}
    tree2 := &TreeNode{4, nil, nil}
    tree3 := &TreeNode{7, nil, nil}
    tree4 := &TreeNode{6, nil, nil}
    tree5 := &TreeNode{8, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := getMinimumDifference(tree1)
    fmt.Println(r) // 1
}
func getMinimumDifference(root *TreeNode) int {
    // ......
}
答案

分析:返回二叉搜索树,任意两不同节点值之间的最小差值。

由于这是二叉搜索树,那么结点间的最小差值一定来自相邻结点之间的差值。

我们可以定义两个同步指针,一个 pre 指向当前结点的前一个结点,一个 cur 指向当前结点,两个指针同步移动。

定义 minDiff = math.MaxInt,如果 cur.Val - pre.Val 小于 minDiff,则更新 minDiff 的值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func getMinimumDifference(root *TreeNode) int {
    var traversal func(node *TreeNode)
    var minDiff = math.MaxInt
    var pre *TreeNode
    traversal = func(cur *TreeNode) {
       if cur == nil {
          return
       }
       // 中序遍历:左中右
       traversal(cur.Left)
       if pre != nil {
          if math.Abs(float64(cur.Val-pre.Val)) < float64(minDiff) {
             minDiff = int(math.Abs(float64(cur.Val - pre.Val)))
          }
       }
       pre = cur
       traversal(cur.Right)
    }
    traversal(root)
    return minDiff
}

二叉搜索树中的众数

501. 二叉搜索树中的众数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func main() {
    tree1 := &TreeNode{5, nil, nil}
    tree2 := &TreeNode{4, nil, nil}
    tree3 := &TreeNode{7, nil, nil}
    tree4 := &TreeNode{7, nil, nil}
    tree5 := &TreeNode{7, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree3.Left = tree4
    tree3.Right = tree5
    r := findMode(tree1)
    fmt.Println(r) // [7]
}
func findMode(root *TreeNode) []int {
    // ......
}
答案

也是使用两个指针 pre 和 cur,在遍历二叉树时,统计某个相同元素出现的次数 count。

pre 为 cur 的前一个结点,如果 cur 的值和 pre 的值相等,则 count++,否则 count 置1。

再定义一个 maxCount,保存整个二叉树的出现最多元素的次数,如果 count==maxCount,则将遍历到的元素加入到目标数组 result 中。

如果 count > maxCount,则将 result 设置为只有当前元素的数组(清空前面存入的数据)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
func findMode(root *TreeNode) []int {
    var count = 1              // 某元素出现的次数
    var maxCount = math.MinInt // 二叉树中出现最多元素的次数
    var traversal func(node *TreeNode)
    var pre *TreeNode
    var result = make([]int, 0)
    // 中序遍历
    traversal = func(cur *TreeNode) {
       if cur == nil {
          return
       }
       traversal(cur.Left)
       if pre != nil && pre.Val == cur.Val {
          count++
       } else {
          count = 1
       }
       if count == maxCount {
          result = append(result, cur.Val)
       } else if count > maxCount {
          maxCount = count
          result = []int{}
          result = append(result, cur.Val)
       }
       pre = cur // 将pre后移
       traversal(cur.Right)
    }
    traversal(root)
    return result
}

二叉树的最近公共祖先

236. 二叉树的最近公共祖先

本题较为复杂,可以多加练习。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func main() {
    tree1 := &TreeNode{1, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{3, nil, nil}
    tree4 := &TreeNode{4, nil, nil}
    tree5 := &TreeNode{5, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree2.Left = tree4
    tree2.Right = tree5
    r := lowestCommonAncestor(tree1, tree4, tree5)
    fmt.Println(r) // &{2 0xc000008090 0xc0000080a8}
}

func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    // ......
}
答案

我们要判断当前结点 node 的左、右结点是否包含 p 或 q,如果包含,则返回当前结点 node。

由于需要先遍历左右孩子结点,再向上返回,所以我们需要使用后序遍历。

遍历时,如果左不为空,右也不为空,则当前结点就是 p 和 q 的最近公共祖先。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    if root == nil {
       return nil
    }
    if root == p || root == q {
       return root
    }
    left := lowestCommonAncestor(root.Left, p, q)
    right := lowestCommonAncestor(root.Right, p, q)
    if left != nil && right != nil {
       return root
    } else if left != nil {
       return left
    } else if left == nil {
       return right
    } else {
       return nil
    }
}

二叉搜索树的最近公共祖先

235. 二叉搜索树的最近公共祖先

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func main() {
    tree1 := &TreeNode{4, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{6, nil, nil}
    tree4 := &TreeNode{1, nil, nil}
    tree5 := &TreeNode{3, nil, nil}
    tree6 := &TreeNode{5, nil, nil}
    tree7 := &TreeNode{7, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree2.Left = tree4
    tree2.Right = tree5
    tree3.Left = tree6
    tree3.Right = tree7
    r := lowestCommonAncestor(tree1, tree4, tree5)
    fmt.Println(r) // &{2 0xc000008090 0xc0000080a8}
}
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    // ......
}
答案

递归

由于这是二叉搜索树,所以我们可以根据 p 和 q 的值,确定搜索的方向。

如果 p、q 的值都小于 root 的值,那么应该往 root 的左子树去搜索;

如果 p、q 的值都大于 root 的值,那么应该往 root 的右子树去搜索;

否则,root 就是 p、q 的最近公共祖先(这一点结论很重要)。

为什么能得到最后的结论呢?

因为:假设 q 大于 p,如果 root 继续往左子树搜索,那么 p 就被排除掉了,同理往右,q 被排除掉了,所以 p、q 的最近公共祖先就是 root。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func lowestCommonAncestor1(root, p, q *TreeNode) *TreeNode {
    if root == nil {
       return nil
    }
    if p.Val < root.Val && q.Val < root.Val {
       return lowestCommonAncestor1(root.Left, p, q)
    } else if p.Val > root.Val && q.Val > root.Val {
       return lowestCommonAncestor1(root.Right, p, q)
    } else {
       return root
    }
}

迭代法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func lowestCommonAncestor2(root, p, q *TreeNode) *TreeNode {
    if root == nil {
       return nil
    }
    for root != nil {
       if p.Val < root.Val && q.Val < root.Val {
          root = root.Left
       } else if p.Val > root.Val && q.Val > root.Val {
          root = root.Right
       } else {
          return root
       }
    }
    return nil
}

二叉搜索树中的插入操作

701. 二叉搜索树中的插入操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func main() {
    tree1 := &TreeNode{4, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{6, nil, nil}
    tree4 := &TreeNode{1, nil, nil}
    tree5 := &TreeNode{3, nil, nil}
    tree6 := &TreeNode{5, nil, nil}
    tree7 := &TreeNode{7, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree2.Left = tree4
    tree2.Right = tree5
    tree3.Left = tree6
    tree3.Right = tree7
    r := insertIntoBST(tree1, 9)
    fmt.Println(r) // &{4 0xc000008060 0xc000008078}
}
func insertIntoBST(root *TreeNode, val int) *TreeNode {
    // ......
}
答案

在二叉搜索树插入结点时,我们需要明确一点,那就是:我们可以直接在叶子结点处插入结点,而不需要调整二叉搜索树的结构。

明确了这一点以后,二叉树的插入操作就变得简单了。

我们只需要根据插入的值 val 进行分支查找,当找到的结点 root 为空时,说明这就是我们应该插入的位置。

那么,如何将该位置添加到二叉树中呢?

我们可以给 traversal(遍历函数)添加一个返回值,如果我们是向左搜索,且找到了目标位置,那么 root 的左孩子就是 traversal 函数的返回值;反之,向右搜索,右孩子是 traversal 函数的返回值。

这样就把返回结点和二叉树连接起来了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
func insertIntoBST(root *TreeNode, val int) *TreeNode {
    if root == nil { // 说明找到了插入的位置
       root = &TreeNode{val, nil, nil}
       return root
    }
    if root.Val < val { // 往右搜索
       root.Right = insertIntoBST(root.Right, val)
    } else { // 往左搜索
       root.Left = insertIntoBST(root.Left, val)
    }
    return root
}

删除二叉搜索树中的节点

本题较为复杂,可以多加练习。

450. 删除二叉搜索树中的节点

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func main() {
    tree1 := &TreeNode{4, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{6, nil, nil}
    tree4 := &TreeNode{1, nil, nil}
    tree5 := &TreeNode{3, nil, nil}
    tree6 := &TreeNode{5, nil, nil}
    tree7 := &TreeNode{7, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree2.Left = tree4
    tree2.Right = tree5
    tree3.Left = tree6
    tree3.Right = tree7
    r := deleteNode(tree1, 4)
    fmt.Println(r) // &{6 0xc0000080c0 0xc0000080d8}
}
func deleteNode(root *TreeNode, key int) *TreeNode {
	// ......
}
答案

删除结点时,主要分为下面 5 种情况。

1.未找到要删除的结点:返回空。

2.删除的结点为叶子结点(左右孩子为空):返回空,在递归调用的过程中,会让上一次递归的指针指向下一次递归的返回值。

这样就让当前结点的上层结点(左右指针根据具体情况决定)指向了空(相当于删除了该结点)。

3.要删除结点的左孩子为空,但右孩子不为空:返回右孩子结点(用右孩子替换当前结点)。

4.要删除结点的右孩子为空,但左孩子不为空:返回左孩子结点(用左孩子替换当前结点)。

5.要删除结点(A)的左右孩子都不为空:我们让它的右孩子(B)继位,需要找到右孩子 B 的孩子中最左侧的孩子C,让 B 的左孩子 C 的左孩子来指向删除结点 A 的左孩子 D(因为小到大的顺序为D、A(删除)、C、B(继位)) 第 5 种情况是最复杂的,建议画图理解。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 首先要明确函数的返回值是什么:删除某个结点之后的根节点
func deleteNode(root *TreeNode, key int) *TreeNode {
    if root == nil {
       return nil
    }
    if root.Val == key {
       if root.Left == nil && root.Right == nil { // 叶子结点,返回nil
          return nil
       } else if root.Left != nil && root.Right == nil { // 左不为空,左孩子继承
          return root.Left
       } else if root.Right != nil && root.Left == nil { // 右不为空,右孩子继承
          return root.Right
       } else { // 左右都不为空
          cur := root.Right // 要继承的结点
          // 找到要继承结点的最左侧孩子的左侧位置(用来接收删除结点的左孩子)
          // 如果cur的没有左孩子,那么不会进入for循环,就用cur的左孩子来解释删除结点的左孩子
          for cur.Left != nil {  // 这里要用for,找到cur的最深层、左侧的孩子结点
             cur = cur.Left
          }
          cur.Left = root.Left // cur的左孩子等于删除结点的左孩子
          return root.Right    // 用右孩子去继承(跳过要删除的结点)
       }
    }
    if key < root.Val { // 删除的值小于根节点的值,往左搜索
       // 这里要用root.Left来接收删除之后的根节点,才能让数的指向连接起来
       // 这里也包含向上回溯的过程
       root.Left = deleteNode(root.Left, key)
    }
    if key > root.Val {
       root.Right = deleteNode(root.Right, key)
    }
    return root
}

修剪二叉搜索树

669. 修剪二叉搜索树

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func main() {
    tree1 := &TreeNode{4, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{6, nil, nil}
    tree4 := &TreeNode{1, nil, nil}
    tree5 := &TreeNode{3, nil, nil}
    tree6 := &TreeNode{5, nil, nil}
    tree7 := &TreeNode{7, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree2.Left = tree4
    tree2.Right = tree5
    tree3.Left = tree6
    tree3.Right = tree7
    r := trimBST(tree1, 2, 5)
    fmt.Println(r) // &{4 0xc0000080c0 0xc0000080d8}
}
func trimBST(root *TreeNode, low int, high int) *TreeNode {
    // ......
}
答案

本题需要对二叉搜索树进行修剪,删除掉不在指定范围的结点。

函数的返回值是某子树修剪后的根结点。

当 root 为空时,直接返回 nil;

当 root 的值小于 low 时,应该往右搜索(左边全部舍弃,对右边进行修剪),但我们不能直接返回 root.Right, 而是应该递归调用裁剪函数 trimBST(),传入参数 root.Right。

因为 root.Right 的子树中也可能有不在 low 到 high 之间的结点。

当 root 的值大于 high 时,应该往左搜索(右边全部舍弃,对左边进行修剪),同理,我们不能直接返回root.Left。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func trimBST(root *TreeNode, low int, high int) *TreeNode {
    if root == nil {
       return nil
    }
    if root.Val < low { // 左侧全部舍弃,对右侧进行修剪
       return trimBST(root.Right, low, high)
    } else if root.Val > high { // 右侧全部舍弃,对左侧进行修剪
       return trimBST(root.Left, low, high)
    }
    root.Left = trimBST(root.Left, low, high) // 用root.Left来接收对左子树修剪之后的结点(连接各个结点和回溯过程)
    root.Right = trimBST(root.Right, low, high)
    return root
}

将有序数组转换为二叉搜索树

108. 将有序数组转换为二叉搜索树

1
2
3
4
5
6
7
8
func main() {
    nums := []int{-10, -3, 0, 5, 9}
    r := sortedArrayToBST(nums)
    fmt.Println(r) // &{0 0xc0000080c0 0xc0000080d8}
}
func sortedArrayToBST(nums []int) *TreeNode {
    // ......
}
答案

为了保证构造的二叉树是平衡二叉树(左右高度差不超过 1),我们在构造二叉树时,应该选择最中间位置的元素作为根结点,然后对左右数组进行递归调用,从而构造完整的二叉树。

在对数组左右区间进行调整时,我们采用统一的左闭右闭区间。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func sortedArrayToBST(nums []int) *TreeNode {
    // 
    var traversal func(nums []int, left int, right int) *TreeNode
    traversal = func(nums []int, left, right int) *TreeNode {
       if left > right { // 非法区间
          return nil
       }
       // 采用前序遍历
       mid := left + (right-left)>>1
       root := &TreeNode{nums[mid], nil, nil}
       root.Left = traversal(nums, left, mid-1) // 对左数组构建二叉树,返回构建好的头结点,让root的左孩子等于该结点
       root.Right = traversal(nums, mid+1, right)
       return root
    }
    return traversal(nums, 0, len(nums)-1)
}

把二叉搜索树转换为累加树

538. 把二叉搜索树转换为累加树

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func main() {
    tree1 := &TreeNode{4, nil, nil}
    tree2 := &TreeNode{2, nil, nil}
    tree3 := &TreeNode{6, nil, nil}
    tree4 := &TreeNode{1, nil, nil}
    tree5 := &TreeNode{3, nil, nil}
    tree6 := &TreeNode{5, nil, nil}
    tree7 := &TreeNode{7, nil, nil}
    tree1.Left = tree2
    tree1.Right = tree3
    tree2.Left = tree4
    tree2.Right = tree5
    tree3.Left = tree6
    tree3.Right = tree7
    r := convertBST(tree1)
    fmt.Println(r)  &{22 0xc000008060 0xc000008078}
}
func convertBST(root *TreeNode) *TreeNode {
    // ......
}
答案

由于需要把大于当前结点的值都累加到本结点中,所以我们遍历的顺序为:右中左

右中左,就是中序遍历的逆过程。

使用 pre 指针指向当前结点 cur 的前一个结点,让当前结点的值等于 cur 的值加上 pre 的值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
func convertBST(root *TreeNode) *TreeNode {
    var pre *TreeNode
    var traversal func(cur *TreeNode)
    traversal = func(cur *TreeNode) {
       if cur == nil {
          return
       }
       traversal(cur.Right)
       if pre != nil {
          cur.Val += pre.Val
       }
       pre = cur
       traversal(cur.Left)
    }
    traversal(root)
    return root
}
0%