【算法题】二叉树面试题

算法题二叉树部分面试题,在面试前是很有必要针对性的刷一些题,很多朋友的实战能力很强,但是理论比较薄弱,面试前不做准备是很吃亏的。算法题作为面试的核心环节,是代码编写能力的重要体现。

本章节主要对树的常见面试题进行总结。

前序遍历

题目:144. 二叉树的前序遍历 。核心思想:栈、根左右

代码如下:

Golang 复制代码
package main
import "fmt"
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

func preorderTraversal(root *TreeNode) []int {
    if root == nil {
        return []int{}
    }
    stack := []*TreeNode{root}
    ans := []int{}
    for len(stack) > 0 {
        root = stack[len(stack)-1]
        ans = append(ans, root.Val)
        stack = stack[:len(stack)-1]
        if root.Right != nil {
            stack = append(stack, root.Right)
        }
        if root.Left != nil {
            stack = append(stack, root.Left)
        }
    }
    return ans
}
func main() {
    var root *TreeNode = &TreeNode{
        Val: 1,
        Left: &TreeNode{
            Val:   2,
            Left:  nil,
            Right: nil,
        },
        Right: &TreeNode{
            Val:   3,
            Left:  nil,
            Right: nil,
        },
    }

    fmt.Println("Hello World!", preorderTraversal(root))
}

中序遍历

题目94. 二叉树的中序遍历。 核心思想:栈,左根右

Golang 复制代码
package main
import "fmt"
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

func inorderTraversal(root *TreeNode) []int {
    stack := []*TreeNode{}
    ans := []int{}
    for root != nil || len(stack) > 0 {
        for root != nil {
            stack = append(stack, root)
            root = root.Left
        }
        root = stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        ans = append(ans, root.Val)
        if root.Right != nil {
            root = root.Right
        } else {
            root = nil
        }
    }
    return ans
}
func main() {
    var root *TreeNode = &TreeNode{
        Val: 1,
        Left: &TreeNode{
            Val:   2,
            Left:  nil,
            Right: nil,
        },
        Right: &TreeNode{
            Val:   3,
            Left:  nil,
            Right: nil,
        },
    }

    fmt.Println(inorderTraversal(root))
}

后序遍历

题目145. 二叉树的后序遍历。 核心思想:栈,左右根

Golang 复制代码
package main
import "fmt"
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

func postorderTraversal(root *TreeNode) []int {
    stack := []*TreeNode{}
    ans := []int{}
    var pre *TreeNode = nil
    for root != nil || len(stack) > 0 {
        for root != nil {
            stack = append(stack, root)
            root = root.Left
        }
        root = stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        if root.Right == nil || root.Right == pre {
            ans = append(ans, root.Val)
            pre = root
            root = nil
        } else {
            stack = append(stack, root)
            root = root.Right
        }
    }
    return ans
}
func main() {
    var root *TreeNode = &TreeNode{
        Val: 1,
        Left: &TreeNode{
            Val:   2,
            Left:  nil,
            Right: nil,
        },
        Right: &TreeNode{
            Val:   3,
            Left:  nil,
            Right: nil,
        },
    }
    fmt.Println(postorderTraversal(root))
}

按照层遍历

按层遍历使用队列就可以来解决问题。

题目102. 二叉树的层序遍历。 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

Golang 复制代码
package main

import "fmt"

type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

func levelOrder(root *TreeNode) [][]int {
    if root == nil {
        return [][]int{}
    }
    stack := []*TreeNode{root}
    ans := [][]int{}
    for len(stack) > 0 {
        temp := []int{}
        size := len(stack)
        for i := 0; i < size; i++ {
            node := stack[0]
            stack = stack[1:]
            temp = append(temp, node.Val)
            if node.Left != nil {
                    stack = append(stack, node.Left)
            }
            if node.Right != nil {
                    stack = append(stack, node.Right)
            }
        }
        ans = append(ans, temp)
    }
    return ans
}
func main() {
    var root *TreeNode = &TreeNode{
        Val: 1,
        Left: &TreeNode{
            Val:   2,
            Left:  nil,
            Right: nil,
        },
        Right: &TreeNode{
            Val:   3,
            Left:  nil,
            Right: nil,
        },
    }
    fmt.Println(levelOrder(root))
}

相似题目:

  1. 题目:103. 二叉树的锯齿形层序遍历

  2. 题目:107. 二叉树的层序遍历 II

  3. 题目:199. 二叉树的右视图

  4. 题目:二叉树的左视图

  5. 题目:LCR 144. 翻转二叉树。 这里也可以使用按照其他形式进行遍历,遍历出来所有节点后,对节点进行反转即可。

  6. 题目:958. 二叉树的完全性检验。 核心:还是按照层遍历,判断连续的中间是否空值存在。

go 复制代码
isFindNil := false
for i:=0; i<len(stack); i++ {
    if stack[i] != nil && isFindNil {
        return false
    }
    if stack[i] == nil {
        isFindNil = true
    }
}
return true
  1. 题目:1302. 层数最深叶子节点的和。核心:还是按层遍历。记录每层的最大和。

二叉树的最大深度

104. 二叉树的最大深度

核心:递归

go 复制代码
func max(a int, b int) int {
    if a > b {
        return a
    }
    return b
}
func maxDepth(root *TreeNode) int {
    if root == nil {
        return 0
    }
    lh := maxDepth(root.Left)
    rh := maxDepth(root.Right)
    return max(lh, rh) + 1
}

二叉树的所有路径

题目:257. 二叉树的所有路径 给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

核心点:就是递归,注意数字转化为字符串的方法 strconv.Itoa()

Golang 复制代码
func binaryTreePaths(root *TreeNode) []string {
    ans := []string{}
    var dfs func(root *TreeNode, path string)
    dfs = func(root *TreeNode, path string) {
        if root.Left == nil && root.Right == nil {
            path = path +  strconv.Itoa(root.Val)
            ans = append(ans, path)
            return
        }
        path = path  + strconv.Itoa(root.Val)+ "->"
        if root.Left != nil {
            dfs(root.Left, path)
        }
        if root.Right != nil {
            dfs(root.Right, path)
        }
    }
    dfs(root, "")
    return ans;
}

平衡二叉树

题目:110. 平衡二叉树 平衡二叉树: 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。核心:还是递归,用-1 作为不平衡的特殊值,也可以结束循环

Golang 复制代码
func max(a int, b int) int {
    if a > b {
        return a
    }
    return b
}
func abs(a int, b int) int {
    if a - b > 0 {
        return a - b
    }
    return b - a
}
func isBalanced(root *TreeNode) bool {
    var height func(root *TreeNode) int
    height = func(root *TreeNode) int {
        if root == nil {
            return 0
        }
        lh := height(root.Left)
        rh := height(root.Right)
        if lh == -1 || rh == -1 || abs(lh, rh) > 1 {
            return -1
        }
        return max(lh, rh) + 1
    }
    if (height(root)>-1){
        return true
    }
    return false
}

二叉树的直径

题目:543. 二叉树的直径 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。核心:递归分别计算左右两个节点的长度。

go 复制代码
func max(a, b int) int{
    if a > b {
        return a
    }
    return b
}
func diameterOfBinaryTree(root *TreeNode) int {
    maxDepth := 0
    var dfs func(root *TreeNode) int
    dfs = func(root *TreeNode) int {
        if root == nil {
            return 0
        }
        lh := dfs(root.Left)
        rh := dfs(root.Right)
        depth := max(lh, rh) + 1
        maxDepth = max(maxDepth, lh + rh + 1)
        return depth        
    }
    dfs(root)
    return maxDepth-1
}

相似题目: 题目:124. 二叉树中的最大路径和。核心:递归返回的是到此节点的最大值是多少。

go 复制代码
func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}
func maxPathSum(root *TreeNode) int {
    if root == nil{
        return 0
    }
    maxGain := ^int(^uint(0) >> 1)
    var dfs func(root *TreeNode) int
    dfs = func(root *TreeNode) int {
        if root == nil {
            return 0
        }
        lh := max(dfs(root.Left), 0)
        rh := max(dfs(root.Right),0)
        maxGain = max(maxGain, lh + rh + root.Val)
        return max(lh, rh) + root.Val
    }
    dfs(root)
    return maxGain
}

二叉树的最近公共祖先

题目:236. 二叉树的最近公共祖先。给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

核心:递归, 返回 是否包含 其中的一个节点。 赋值的条件是 左右都包含,或者是当前为节点值为其中一个,左右包含一个。

Golang 复制代码
 func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
  var dfs func(root *TreeNode, p, q *TreeNode) bool
  var ans *TreeNode = nil
  dfs = func(root, p, q *TreeNode) bool{
      if root == nil {
          return false
      }
      lh := dfs(root.Left, p, q)
      rh := dfs(root.Right, p, q)
      if (lh && rh) || ( (root.Val == p.Val || root.Val == q.Val) && (lh || rh) ) {
          ans = root
          return true
      }
      return lh || rh || root.Val == p.Val || root.Val == q.Val
  }
  dfs(root, p, q)
  return ans
}

路径类型题目

核心: 这种类型的题目还是递归,将路径记录下来。

  1. 题目:113. 路径总和 II 。给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
go 复制代码
func pathSum(root *TreeNode, targetSum int) [][]int {
    ans := [][]int{}
    var dfs func(root *TreeNode, path []int, sum int)
    dfs = func(root *TreeNode, path []int, sum int) {
        if root.Left == nil && root.Right == nil {
            if sum + root.Val == targetSum {
                path = append(path, root.Val)
                ans = append(ans, append([]int(nil), path...))
                return
            }
        }
        path = append(path, root.Val)
        if root.Left != nil {
            dfs(root.Left, path, sum + root.Val)
        }
        if root.Right != nil {
            dfs(root.Right, path, sum + root.Val)
        }
    }
    dfs(root, []int{}, 0)
    return ans
}
  1. 求根到叶子的所有和。 题目:求根到叶子的所有和
go 复制代码
func sumNumbers(root *TreeNode) int {
    total := 0
    var dfs func(root *TreeNode, sum int)
    dfs = func(root *TreeNode, sum int) {
        if root.Left == nil && root.Right == nil {
            total += root.Val + sum * 10
        }
        if root.Left != nil {
            dfs(root.Left, root.Val + sum * 10)
        }
        if root.Right != nil {
            dfs(root.Right, root.Val + sum * 10)
        }
    }
    dfs(root, 0)
    return total
}
  1. 获得所有的路径。题目:129. 求根节点到叶节点数字之和
相关推荐
聪明的笨猪猪15 小时前
Java Redis “缓存设计”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
聪明的笨猪猪16 小时前
Java Redis “运维”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
苏打水com16 小时前
JavaScript 面试题标准答案模板(对应前文核心考点)
javascript·面试
南北是北北20 小时前
JetPack WorkManager
面试
uhakadotcom21 小时前
在chrome浏览器插件之中,options.html和options.js常用来做什么事情
前端·javascript·面试
想想就想想21 小时前
线程池执行流程详解
面试
程序员清风1 天前
Dubbo RPCContext存储一些通用数据,这个用手动清除吗?
java·后端·面试
南北是北北1 天前
JetPack ViewBinding
面试
南北是北北1 天前
jetpack ViewModel
面试
渣哥1 天前
Lazy能否有效解决循环依赖?答案比你想的复杂
javascript·后端·面试