【算法题】二叉树面试题

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

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

前序遍历

题目: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 小时前
1.13草花互动面试
面试·职场和发展
阿蒙Amon17 小时前
C#每日面试题-常量和只读变量的区别
java·面试·c#
程序员小白条18 小时前
面试 Java 基础八股文十问十答第八期
java·开发语言·数据库·spring·面试·职场和发展·毕设
xlp666hub19 小时前
Linux 设备模型学习笔记(1)
面试·嵌入式
南囝coding20 小时前
CSS终于能做瀑布流了!三行代码搞定,告别JavaScript布局
前端·后端·面试
踏浪无痕21 小时前
Go 的协程是线程吗?别被"轻量级线程"骗了
后端·面试·go
一只叫煤球的猫1 天前
为什么Java里面,Service 层不直接返回 Result 对象?
java·spring boot·面试
求梦8201 天前
字节前端面试复盘
面试·职场和发展
C雨后彩虹1 天前
书籍叠放问题
java·数据结构·算法·华为·面试
码农水水1 天前
中国电网Java面试被问:流批一体架构的实现和状态管理
java·c语言·开发语言·面试·职场和发展·架构·kafka