二叉树常见面试题(Go语言实现)

开心一刻

       语文诗歌题三大基本方法:诗人被贬法,诗人开心法,诗人思乡法。
       数学做题三大基本方法:肉眼观察法,暴力代值法,显然成立法。
       英语阅读题三大基本方法:硬币投掷法,笔尖坠落指向法,投骰法。
       物理做题三大基本方法:直接代公式法,保守少选法,一看就不对法。
       政治大题三大基本方法:照搬材料原文法,照搬选择题干法,照搬选择选项法。
       历史史论题三大基本方法:他说的有理法,他说的片面法,他说的扯淡法。
       地理做题三大基本方法:看地图法,画地图法,创造地图法。

最近面试被问到二叉树的相关问题, 有的没有回答好, 趁此机会记录一些网上常见的面试题目, 做些总结。

二叉树的结构

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

求二叉树的最大深度

       给定一个二叉树,找出其最大深度。

       二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。

       说明: 叶子节点是指没有子节点的节点。

       算法思路:节点为空时,返回节点深度为0;递归计算左右子树的深度,然后用较大值加上父节点的深度1;然后返回,最终返回到根节点时即可求得最大深度。

func maxDepth(root *TreeNode) int {
    if root == nil {
        return 0
    }
    var left = maxDepth(root.Left)
    var right = maxDepth(root.Right)
    if left > right {
        return left + 1
    }
    return right + 1
}

求二叉树的最小深度

       给定一个二叉树,找出其最小深度。

       最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

       说明:叶子节点是指没有子节点的节点。

       算法思路:根节点需要特殊判断,为空时返回深度为0;对于叶子节点,不计算叶子节点的左右子树深度,而是直接返回深度为1;对于只有左子树的节点,左子树深度标记为不可达,只有右子树的节点同理;然后计算左右子树的最小深度,用最小深度加上父节点的深度1

func minDepth(root *TreeNode) int {
    if root == nil {
        return 0
    }
    return getMin(root)
}

func getMin(root *TreeNode) int {
    if root == nil {
        return int(^uint(0) >> 1)
    }
    if root.Left == nil && root.Right == nil {
        return 1
    }
    return Min(getMin(root.Left), getMin(root.Right)) + 1
}

func Min(x, y int) int {
    if x > y {
        return y
    }
    return x
}

求二叉树中节点的个数

       算法思路:递归计算左右子树节点个数后,返回左右子树节点个数和父节点个数的和即可

func numOfTreeNode(root *TreeNode) int {
    if root == nil {
        return 0
    }
    var left = numOfTreeNode(root.Left)
    var right = numOfTreeNode(root.Right)
    return left + right + 1
}

求二叉树中叶子节点的个数

       算法思路:叶子节点需要单独判断,并返回结果1;然后递归计算左子树叶子节点数量和右子树叶子节点数量,然后相加并返回

func numOfNoChildNode(root *TreeNode) int {
    if root == nil {
        return 0
    }
    if root.Left == nil && root.Right == nil {
        return 1
    }
    var left = numOfTreeNode(root.Left)
    var right = numOfTreeNode(root.Right)
    return left + right
}

判断二叉树是否是平衡二叉树

       输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
       算法思路:判断是否是平衡二叉树属于求树的最大深度的变种。当判断某一节点的左右子树的深度之差的绝对值大于1时,那么整棵二叉树就不是平衡二叉树了,所以在此时可以返回一个特殊值来标记(此处用的-1,因为求二叉树深度不可能出现负值),那么最终的结果也会是这个特殊值,根据这个特殊值就可以判断这个二叉树是否是一个平衡二叉树。

func isBalanced(root *TreeNode) bool {
    if root == nil {
        return true
    }
    return getDepth(root) != -1
}
func getDepth(root *TreeNode) int {
    if root == nil {
        return 0
    }
    var left = getDepth(root.Left)
    var right = getDepth(root.Right)
    if left == -1 || right == -1 || Abs(left, right) > 1 {
        return -1
    }
    if left > right {
        return left + 1
    } else {
        return right + 1
    }
}
func Abs(x, y int) int {
    if x > y {
        return x - y
    } else {
        return y - x
    }
}

求二叉树中第K层节点的个数

       与求叶子节点的数量相似, 只不过判断叶子节点的时候修改成判断当前k是否为1

func numOfKLevelNode(root *TreeNode, k int) int {
    if root == nil {
        return 0
    }
    if k == 1 {
        return 1
    }
    var left = numOfKLevelNode(root.Left, k - 1)
    var right = numOfKLevelNode(root.Right, k - 1)
    return left + right
}

判断二叉树是否是完全二叉树

       若设二叉树的深度为 h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。(注:第 h 层可能包含 1~ 2^h 个节点。)
       根据完全二叉树的定义, 使用层次遍历即可解决.

func isCompleteTree(root *TreeNode) bool {
    if root == nil {
        return true
    }
    var queue = []*TreeNode{root}
    var num = 1
    for i := 0; len(queue) != 0; i++ {
        var q []*TreeNode
        var flag bool
        for j := 0; j < len(queue); j++ {
            node := queue[j]
            if flag && node.Left != nil {
                return false
            }
            if node.Left != nil {
                q = append(q, node.Left)
            } else {
                flag = true
            }
            if flag && node.Right != nil {
                return false
            }
            if node.Right != nil {
                q = append(q, node.Right)
            } else {
                flag = true
            }
        }
        if len(q) != 0 {
            if len(queue) != num {
                return false
            }
            num *= 2
        }
        queue = q
    }
    return true
}

两个二叉树是否完全相同

func isSameTree(p *TreeNode, q *TreeNode) bool {
    if p == nil && q == nil {
        return true
    }
    if p == nil || q == nil || p.Val != q.Val {
        return false
    }
    return isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)
}

两个二叉树是否互为镜像

func isMirror(p *TreeNode, q *TreeNode) bool {
    if p == nil && q == nil {
        return true
    }
    if p == nil || q == nil || p.Val != q.Val {
        return false
    }
    return isMirror(p.Left, q.Right) && isSameTree(p.Right, q.Left)
}

翻转二叉树or镜像二叉树

func mirrorTree(root *TreeNode) *TreeNode {
    var dfs func(root *TreeNode)
    dfs = func(root *TreeNode) {
        if root == nil {
            return
        }
        dfs(root.Left)
        dfs(root.Right)
        root.Left, root.Right = root.Right, root.Left
    }
    dfs(root)
    return root
}

二叉树的最近公共祖先

func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    if root == nil {
        return nil
    }
    if root.Val == p.Val || root.Val == q.Val {
        return root
    }
    var left = lowestCommonAncestor(root.Left, p, q)
    var right = lowestCommonAncestor(root.Right, p, q)
    if left != nil && right != nil {
        return root
    }
    if left == nil {
        return right
    }
    return left
}

二叉树的前序遍历

func preorderTraversal(root *TreeNode) []int {
    var ret []int
    var preorder func(root *TreeNode) 
    preorder = func(root *TreeNode) {
        if root == nil {
            return
        }
        ret = append(ret, root.Val)
        preorder(root.Left)
        preorder(root.Right)
    }
    preorder(root)
    return ret
}
func preorderTraversal(root *TreeNode) []int {
    if root == nil {
        return nil
    }
    var ret []int
    var stack = []*TreeNode{root}
    for len(stack) != 0 {
        node := stack[len(stack) - 1]
        stack = stack[: len(stack) - 1]
        ret = append(ret, node.Val)
        if node.Right != nil {
            stack = append(stack, node.Right)
        }
        if node.Left != nil {
            stack = append(stack, node.Left)
        }
    }
    return ret
}

二叉树的中序遍历

func inorderTraversal(root *TreeNode) []int {
    var ret []int
    var inorder func(root *TreeNode) 
    inorder = func(root *TreeNode) {
        if root == nil {
            return
        }
        inorder(root.Left)
        ret = append(ret, root.Val)
        inorder(root.Right)
    }
    inorder(root)
    return ret
}
func inorderTraversal(root *TreeNode) []int {
    var (
        ret []int
        stack []*TreeNode
        cur *TreeNode
    )
    cur = root
    for len(stack) != 0 || cur != nil {
        for cur != nil {
            stack = append(stack, cur)
            cur = cur.Left
        }
        node := stack[len(stack) - 1]
        stack = stack[: len(stack) - 1]
        ret = append(ret, node.Val)
        cur = node.Right
    }
    return ret
}

二叉树的后序遍历

func postorderTraversal(root *TreeNode) []int {
    var ret []int
    var postorder func(root *TreeNode)
    postorder = func(root *TreeNode) {
        if root == nil {
            return
        }
        postorder(root.Left)
        postorder(root.Right)
        ret = append(ret, root.Val)
    }
    postorder(root)
    return ret
}
func postorderTraversal(root *TreeNode) []int {
    var (
        ret []int
        stack1 []*TreeNode
    )
    if root == nil {
        return nil
    }
    stack1 = append(stack1, root)
    for len(stack1) != 0 {
        node := stack1[len(stack1) - 1]
        stack1 = stack1[: len(stack1) - 1]
        ret = append(ret, node.Val)
        if node.Left != nil {
            stack1 = append(stack1, node.Left)
        }
        if node.Right != nil {
            stack1 = append(stack1, node.Right)
        }
    }
    for i, j := 0, len(ret) - 1; i < j; i, j = i + 1, j - 1 {
        ret[i], ret[j] = ret[j], ret[i]
    }
    return ret
}

二叉树中路径和为k的路径

func pathSum(root *TreeNode, targetSum int) [][]int {
    var (
        ret [][]int
        path []int
    )
    var dfs func(root *TreeNode, target int) 
    dfs = func(root *TreeNode, target int) {
        if root == nil {
            return
        }
        if root.Left == nil && root.Right == nil {
            if root.Val == target {
                tmp := append(path, target)
                ret = append(ret, append([]int(nil), tmp...))
            }
            return
        }
        path = append(path, root.Val)
        dfs(root.Left, target - root.Val)
        dfs(root.Right, target - root.Val)
        path = path[: len(path) - 1]
    }
    dfs(root, targetSum)
    return ret
}

二叉树层次遍历

func levelOrder(root *TreeNode) [][]int {
    if root == nil {
        return nil
    }
    var queue = []*TreeNode{root}
    var ret [][]int
    for i := 0; len(queue) != 0; i++ {
        var q []*TreeNode
        ret = append(ret, []int(nil))
        for j := 0; j < len(queue); j++ {
            node := queue[j]
            ret[i] = append(ret[i], node.Val)
            if node.Left != nil {
                q = append(q, node.Left)
            }
            if node.Right != nil {
                q = append(q, node.Right)
            }
        }
        queue = q
    }
    return ret
}

判断二叉树是否是合法的二叉查找树

力扣链接

func isValidBST(root *TreeNode) bool {
    left, right := math.MinInt64, math.MaxInt64
    var in_order func(root *TreeNode, left, right int) bool 
    in_order = func(root *TreeNode, left, right int) bool {
        if root == nil {
            return true
        }
        if left >= root.Val || root.Val >= right {
            return false
        }
        return in_order(root.Left, left, root.Val) && in_order(root.Right, root.Val, right)
    }
    return in_order(root, left, right)
}
func isValidBST(root *TreeNode) bool {
    var (
        stack []*TreeNode
        cur *TreeNode
        pre int
    )
    if root == nil {
        return true
    }
    pre = -1 << 63
    cur = root
    for cur != nil || len(stack) != 0 {
        for cur != nil {
            stack = append(stack, cur)
            cur = cur.Left
        }
        node := stack[len(stack) - 1]
        stack = stack[: len(stack) - 1]
        cur = node.Right
        if pre >= node.Val {
            return false
        }
        pre = node.Val
    }
    return true
}

二叉树常见面试题(Go语言实现)

上一篇:Python的注释


下一篇:数组去重的几种方式