二叉树

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. 二叉搜索树中的插入操作(中等)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容