[Go版]算法通关村第八关青铜——轻松搞定二叉树的深度优先经典问题

双指针专题

题目:判断两个树是否相同

题目链接:LeetCode-100. 相同的树
在这里插入图片描述

思路分析:递归 + 左对左、右对右 判断相等

递归遍历这两颗二叉树,判断每个节点,只要存在值不同时就不是相同的树。

Go代码

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

题目:判断二叉树是否镜像对称的

题目链接:LeetCode-101. 对称二叉树
在这里插入图片描述

思路分析:递归 + 左对右、右对左 判断相等

根据镜像的定义,如果这是一个镜像二叉树,那只要把根节点去掉之后可以看做是两个完全对称的二叉树。
所以跟上一题做法基本一致,递归遍历每个子节点,只不过判断时不是左对左、右对右的判断,而是对称判断,即左对右,右对左,只要完全一致,则是对称的二叉树。

Go代码

func isSame(a, b *TreeNode) bool {
    if a == nil && b == nil {
        return true
    }
    if a == nil || b == nil {
        return false
    }
    return a.Val == b.Val && isSame(a.Left, b.Right) && isSame(a.Right, b.Left)
}

func isSymmetric(root *TreeNode) bool {
    if root == nil {
        return true
    }
    return isSame(root.Left, root.Right)
}

题目:合并二叉树

题目链接:LeetCode-617. 合并二叉树
在这里插入图片描述

思路分析:递归 + 左对左、右对右 值相加

同样递归遍历两个树,左对左,右对右,将值相加后赋给新的树节点即可。
注意判断节点为空时,直接取另一颗树对应结点赋值即可。

Go代码

func mergeTrees(root1 *TreeNode, root2 *TreeNode) *TreeNode {
    if root1 == nil && root2 == nil {
        return nil
    }
    if root1 == nil {
        return root2
    }
    if root2 == nil {
        return root1
    }
    newTree := &TreeNode{
        Val : root1.Val + root2.Val,
        Left : mergeTrees(root1.Left, root2.Left),
        Right : mergeTrees(root1.Right, root2.Right),
    }
    return newTree
}

路径专题

题目:找出二叉树的所有路径

题目链接:LeetCode-257. 二叉树的所有路径
在这里插入图片描述

思路分析:递归 + 每个叶子节点对应一条路径

Go代码

func binaryTreePaths(root *TreeNode) (res []string) {
    if root == nil {
        return nil
    }
    var a func(*TreeNode, string)
    a = func(node *TreeNode, path string) {
        if node == nil {
            return
        }
        str := fmt.Sprintf("%d", node.Val)
        path = path+str
        // 叶子节点
        if node.Left == nil && node.Right == nil {
            res = append(res, path)
            return
        }
        a(node.Left, path+"->")
        a(node.Right, path+"->")
    }
    a(root, "")
    return
}

题目:判断二叉树中是否存在路径总和为指定值的路径

题目链接:LeetCode-112. 路径总和
在这里插入图片描述

思路分析:递归

路径总和向下传递的时候减去当前节点的值,这样只要判断是叶子节点并且叶子节点的值等于当时的参数路径总和即代表存在目标路径。

Go代码

func hasPathSum(root *TreeNode, targetSum int) bool {
    if root == nil {
        return false
    }
    if root.Left == nil && root.Right == nil && root.Val == targetSum {
        return true
    }
    return hasPathSum(root.Left, targetSum-root.Val) || hasPathSum(root.Right, targetSum-root.Val)
}

题目:找出二叉树中路径总和为指定值的所有路径

题目链接:LeetCode-113. 路径总和 II
在这里插入图片描述

思路分析:递归 + defer巧妙处理

递归图解

在这里插入图片描述

Go代码

func pathSum(root *TreeNode, targetSum int) (res [][]int) {
    if root == nil {
        return
    }
    arr := []int{}
    var a func(*TreeNode, int)
    a = func (node *TreeNode, sum int) {
        if node == nil {
            return
        }
        sum -= node.Val
        arr = append(arr, node.Val)
        // 从最左叶子节点开始往回遍历时,将该节点从arr中取出
        // 这样能确保arr中的节点数组是从根节点到当前节点的路径节点
        defer func() { arr = arr[:len(arr)-1] }()
        // 找到一条路径
        if node.Left == nil && node.Right == nil && sum == 0 {
            // append([]int{}, arr...) 将arr的元素都放在一个新的切片中加入到res,
            // 否则如果直接将arr将入到res,后面对arr的修改都会同步到res中
            res = append(res, append([]int{}, arr...))
            return
        }
        a(node.Left, sum)
        a(node.Right, sum)
    }
    a(root, targetSum)
    return
}

翻转专题

题目:翻转二叉树

题目链接:LeetCode-226. 翻转二叉树
在这里插入图片描述

思路分析:递归 + 左右节点互换

只需要将每个节点的左右节点互换即可完成翻转。

Go代码

func invertTree(root *TreeNode) *TreeNode {
    if root == nil {
        return root
    }
    root.Left, root.Right = root.Right, root.Left
    invertTree(root.Left)
    invertTree(root.Right)
    return root
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值