二叉树

https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/solution/dai-ma-sui-xiang-lu-dai-ni-xue-tou-er-ch-uq84/

[TOC]

二叉树的遍历方式

144. 二叉树的前序遍历【简单】


// https://leetcode.cn/problems/binary-tree-preorder-traversal/solution/dai-ma-sui-xiang-lu-chi-tou-qian-zhong-hou-xu-de-d/
// 前序遍历是根左右,每次先处理的是中间节点,那么先将跟节点放入栈中,然后将右孩子加入栈,再加入左孩子。
//为什么要先加入 右孩子,再加入左孩子呢? 因为这样出栈的时候才是中左右的顺序。
func preorderTraversal(root *TreeNode) []int {
    ans := make([]int, 0)
    stack := []*TreeNode{root}
    for len(stack) != 0 {
        node := stack[len(stack)-1]
        fmt.Println(node)
        if node == nil {
            stack = stack[:len(stack)-1]
            continue
        }
        ans = append(ans, node.Val)
        stack = stack[:len(stack)-1]      // 栈顶元素出来
        stack = append(stack, node.Right) // 先压栈右节点,再压左节点
        stack = append(stack, node.Left)
    }
    return ans
}

145. 二叉树的后序遍历【简单】

94. 二叉树的中序遍历【简单】

102. 二叉树的层序遍历【中等】


// ============== 解法一: BFS 迭代实现,广度优先遍历 ================
func levelOrder(root *TreeNode) (res [][]int) {
    if root == nil {
        return res
    }
    queue := []*TreeNode{root}
    for len(queue) != 0 {
        var curLevel []int
        size := len(queue)
    
        for i := 0; i < size; i++ {
            node := queue[0]
            curLevel = append(curLevel, node.Val)

            if node.Left != nil {
                queue = append(queue, node.Left)
            }
            if node.Right != nil {
                queue = append(queue, node.Right)
            }
            queue = queue[1:]
        }
        res = append(res, curLevel)
    }

    return res
}

107. 二叉树的层序遍历 II(中等)

func revers(input [][]int) [][]int {
    row := len(input)
    var res [][]int
    for i := row - 1; i >= 0; i-- {
        res = append(res, input[i])
    }
    return res
}

二叉树的属性

//**************** 解法一(递归走起)********************************
//1.判断当前节点的值是否相当
//2.递归判断左子树、右子树是否相等
func isSameTree(p *TreeNode, q *TreeNode) bool {
    if p == nil && q != nil {
        return false
    }

    if p != nil && q == nil {
        return false
    }

    if p == nil && q == nil {
        return true
    }

    if p.Val != q.Val {
        return false
    }
    return isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)
}

101. 对称二叉树【简单】

104. 二叉树的最大深度【简单】


//**************** 解法一(递归走起)********************************

func maxDepth(root *TreeNode) int {
    if root == nil {
        return 0
    }
    left := maxDepth(root.Left)                             // 左子树的最大深度
    right := maxDepth(root.Right)                           // 右子树的最大深度
    return int(math.Max(float64(left), float64(right)) + 1) // 深度加上根节点

}

//**************** 解法二(迭代法走起)********************************

func maxDepth(root *TreeNode) int {
    if root == nil {
        return 0
    }
    queue := []*TreeNode{root} // 辅助队列,根节点入队
    depth := 0                 // 初始化深度为0

    for len(queue) > 0 { // 当队列不为空时,循环以下操作
        size := len(queue)          //当前队列中元素个数size作为限定:当前层级中节点数量
        for i := 0; i < size; i++ { // 遍历当前层级中的节点
            s := queue[0]      // 获取队首元素
            if s.Left != nil { // 如果左子树不为空,左子树入队
                queue = append(queue, s.Left)
            }
            if s.Right != nil { // 如果右子树不为空,右子树入队
                queue = append(queue, s.Right)
            }
            queue = queue[1:] // 队首元素出队
        }
        depth++ // for循环结束后这一层级节点已经访问结束,深度加+1
    }
    return depth
}

111. 二叉树的最小深度【简单】

// ============== 解法一: BFS 迭代实现,广度优先遍历 ================
// https://www.cnblogs.com/Lusai/p/15709094.html
func minDepth(root *TreeNode) int {
    if root == nil {
        return 0
    }
    var queue []*TreeNode       // 查找队列
    queue = append(queue, root) // 将起点加入队列
    depth := 1                  // root 本身就是一层,depth初始化为1
    for len(queue) != 0 {
        size := len(queue)
        // 将当前队列中的所有结点向四周扩散
        for i := 0; i < size; i++ {
            cur := queue[0]
            // 判断是否到终点
            if cur.Left == nil && cur.Right == nil {
                return depth
            }
            // 将 cur的相邻节点加入队列
            if cur.Left != nil {
                queue = append(queue, cur.Left)
            }
            if cur.Right != nil {
                queue = append(queue, cur.Right)
            }
            // 去掉当前节点
            queue = queue[1:]
        }
        // 这里增加步数
        depth++
    }
    return depth
}

// ============== 解法二: DFS   ================

func minDepth(root *TreeNode) int {
    if root == nil {
        return 0
    }
    if root.Left != nil && root.Right == nil {
        return 1 + minDepth(root.Left)
    }
    if root.Right != nil && root.Left == nil {
        return 1 + minDepth(root.Right)
    }
    return 1 + Min(minDepth(root.Left), minDepth(root.Right))
}

222. 完全二叉树的节点个数(中等)

110. 平衡二叉树(中等)

257. 二叉树的所有路径(简单)

404. 左叶子之和【简单】

513. 找树左下角的值【中等】

112. 路径总和【简单】

二叉树的修改和构造

226. 翻转二叉树【简单】

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

654. 最大二叉树(中等)

617. 合并二叉树【简单】

求二叉搜索树的属性

98. 验证二叉搜索树

501. 二叉搜索树中的众数(简单)

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

538. 把二叉搜索树转换为累加树(中等)

700. 二叉搜索树中的搜索(简单)

二叉树公共祖先问题

235. 二叉搜索树的最近公共祖先(简单)

236. 二叉树的最近公共祖先(中等)

// ==================  解法一: DFS 解法   ======================
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    if root == nil {
        return nil
    }

    // 如果p,q为根节点,则公共祖先为根节点
    if root.Val == p.Val || root.Val == q.Val {
        return root
    }

    // 如果p,q在左子树,则公共祖先在左子树查找
    if find(root.Left, p) && find(root.Left, q) {
        return lowestCommonAncestor(root.Left, p, q)
    }

    // 如果p,q在右子树,则公共祖先在右子树查找
    if find(root.Right, p) && find(root.Right, q) {
        return lowestCommonAncestor(root.Right, p, q)

    }

    // 如果p,q分属两侧,则公共祖先为根节点
    return root

}

func find(root, c *TreeNode) bool {
    if root == nil {
        return false
    }
    if root.Val == c.Val {
        return true
    }
    return find(root.Left, c) || find(root.Right, c)

}

// ======  解法二 利用hash表和存储走过的路 ==============
/*思路:我们可以用哈希表存储所有节点的父节点,然后我们就可以利用节点的父节点信息从 p 结点开始不断往上跳,并记录已经访问过的节点
,再从 q 节点开始不断往上跳,如果碰到已经访问过的节点,那么这个节点就是我们要找的最近公共祖先。
算法:从根节点开始遍历整棵二叉树,用哈希表记录每个节点的父节点指针。从 p 节点开始不断往它的祖先移动,并用数据结构记录已经访问过的祖先节点。同样,我们再从 q 节点开始不断往它的祖先移动,如果有祖先已经被访问过,即意味着这是 p 和 q 的深度最深的公共祖先,即 LCA节点。*/
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    parent := map[int]*TreeNode{}
    visited := map[int]bool{}

    var dfs func(*TreeNode)
    dfs = func(r *TreeNode) {
        if r == nil {
            return
        }
        if r.Left != nil {
            parent[r.Left.Val] = r
            dfs(r.Left)
        }
        if r.Right != nil {
            parent[r.Right.Val] = r
            dfs(r.Right)
        }
    }

    dfs(root)

    for p != nil {
        visited[p.Val] = true
        p = parent[p.Val]
    }
    
    for q != nil {
        if visited[q.Val] {
            return q
        }
        q = parent[q.Val] // 从q往上找父节点
    }

    return nil
}

1257. 最小公共区域(会员/中等/LCA)

给你一些区域列表 regions ,每个列表的第一个区域都包含这个列表内所有其他区域。
很自然地,如果区域 X 包含区域 Y ,那么区域 X  比区域 Y 大。
给定两个区域 region1 和 region2 ,找到同时包含这两个区域的 最小 区域。
如果区域列表中 r1 包含 r2 和 r3 ,那么数据保证 r2 不会包含 r3 。
数据同样保证最小公共区域一定存在。

/*
输入:
regions = [["Earth","North America","South America"],
["North America","United States","Canada"],
["United States","New York","Boston"],
["Canada","Ontario","Quebec"],
["South America","Brazil"]],
region1 = "Quebec",
region2 = "New York"
输出:"North America"
*/
/
思路:我们可以用哈希表存储所有节点的父节点,然后我们就可以利用节点的父节点信息从 region1 结点开始不断往上跳,并记录已经访问过的节点
,再从 region2 节点开始不断往上跳,如果碰到已经访问过的节点,那么这个节点就是我们要找的最近公共祖先。
*/
func findSmallestRegion(regions [][]string, region1 string, region2 string) string {

    parent := make(map[string]string)
    visited := make(map[string]bool)

    row, _ := len(regions), len(regions[0])
    for i := 0; i < row; i++ {

        for j := 0; j < len(regions[i]); j++ {
            if j == 0 {  // 很重要,这里必须要把根节点去了
                continue
            }
            parent[regions[i][j]] = regions[i][0]
        }

    }
    // fmt.Println(parent)

    for region1 != "" { // 这里为啥是!=" 呢,因为最上的根节点earth没有父节点,他的父节点就是”“
        visited[region1] = true
        region1 = parent[region1]
    }

    for region2 != "" {
        if visited[region2] {
            return region2
        }
        region2 = parent[region2] // 从q往上找父节点
    }

    return ""
}

二叉搜索树的修改和改造

108. 将有序数组转换为二叉搜索树(简单)

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

669. 修剪二叉搜索树(中等)

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

你可能感兴趣的:(二叉树)