代码随想录制day17|110.平衡二叉树|257. 二叉树的所有路径|404. 左叶子之和|golang

代码随想录制day17

目录

110.平衡二叉树

257. 二叉树的所有路径

404. 左叶子之和


110.平衡二叉树

        给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

示例 1:

给定二叉树 [3,9,20,null,null,15,7]

返回 true 。

题外话:

        咋眼一看这道题目和 104二叉树的最大深度很像,其实有很大区别。

这里强调一波概念:

  • 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数。
  • 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。

但leetcode中强调的深度和高度很明显是按照节点来计算的,如图:

 

        关于根节点的深度究竟是1 还是 0,不同的地方有不一样的标准,leetcode的题目中都是以节点为一度,即根节点深度是1。但维基百科上定义用边为一度,即根节点的深度是0,我们暂时以leetcode为准(毕竟要在这上面刷题)。

        有的同学一定疑惑,为什么104.二叉树的最大深度中求的是二叉树的最大深度,也用的是后序遍历。

        那是因为代码的逻辑其实是求的根节点的高度,而根节点的高度就是这棵树的最大深度,所以才可以使用后序遍历。

本题思路:

递归:

        此时大家应该明白了既然要求比较高度,必然是要后序遍历。

1、明确递归函数的参数和返回值 

        参数:当前传入节点。
        返回值:以当前传入节点为根节点的树的高度。

        那么如何标记左右子树是否差值大于1呢?如果当前传入节点为根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了。

        所以如果已经不是二叉平衡树了,可以返回-1 来标记已经不符合平衡树的规则了。

2、明确终止条件

        递归的过程中依然是遇到空节点了为终止,返回0,表示当前节点为根节点的树高度为0

3、明确单层递归的逻辑

        如何判断以当前传入节点为根节点的二叉树是否是平衡二叉树呢?当然是其左子树高度和其右子树高度的差值。

        分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则则返回-1,表示已经不是二叉平衡树了。

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func isBalanced(root *TreeNode) bool {
    if root == nil {
        return true
    }
    if isBalanced(root.Left) == false || isBalanced(root.Right) == false {
        return false
    }
    l_high := maxdepth(root.Left) 
    r_high := maxdepth(root.Right)
    if abs(l_high - r_high) > 1 {
        return false
    }
    return true
}
func maxdepth(root *TreeNode) int {
    if root == nil {
        return 0
    }
    return max(maxdepth(root.Left), maxdepth(root.Right)) + 1
}
func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}
func abs(a int) int {
    if a <  0 {
        return -a
    }
    return a 
}

257. 二叉树的所有路径

给定一个二叉树,返回所有从根节点到叶子节点的路径。

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

 

思路:

        这道题目要求从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。

        在这道题目中将第一次涉及到回溯,因为我们要把路径记录下来,需要回溯来回退一一个路径在进入另一个路径。

        前序遍历以及回溯的过程如图:

 我们先使用递归的方式,来做前序遍历。要知道递归和回溯就是一家的,本题也需要回溯。

var res []string
func binaryTreePaths(root *TreeNode) []string {
    res = make([]string,0)
    digui(root,"")
    return res
}
func digui(root *TreeNode, s string) {
    if root.Left == nil && root.Right == nil {
        v := s + strconv.Itoa(root.Val)
        res = append(res, v)
        return    
    }
    s = s + strconv.Itoa(root.Val) + "->"        // 中
    if root.Left != nil {                        // 左
        digui(root.Left, s)        
    }
    if root.Right != nil {                       // 右
        digui(root.Right, s)    
    }
}

//以下面例子为例,代码执行过程如下
    1
  2   3

1、s = "" + "1" + "->"        // "1->"
2、root.Left != nil,进行递归
    此时在root.Left里面的root.Left和root.Right == nil {
        v := s + "root.Val"  // "1->" + "2" = "1->2"     
        res = append(res,v )   //存放进res, res = ["1->2"]
        return     // 回溯了,结束该递归函数       
    }
3、root.Right != nil,进行递归
    此时root.Right里面的root.Left和root.Right == nil {
        v := s + "root.Val"    //  "1->" + "3" = "1->3"
        res = append(res, v)   //存放进res, res = ["1->2", "1->3"]
        return   
    }

 

404. 左叶子之和

        计算给定二叉树的所有左叶子之和。

示例:

思路:

        首先要注意是判断左叶子,不是二叉树左侧节点,所以不要上来想着层序遍历。

        因为题目中其实没有说清楚左叶子究竟是什么节点,那么我来给出左叶子的明确定义:如果左节点不为空,且左节点没有左右孩子,那么这个节点的左节点就是左叶子

大家思考一下如下图中二叉树,左叶子之和究竟是多少?

 

其实是0,因为这棵树根本没有左叶子!

但看这个图的左叶子之和是多少?

 相信通过这两个图,大家可以最左叶子的定义有明确理解了。

        那么判断当前节点是不是左叶子是无法判断的,必须要通过节点的父节点来判断其左孩子是不是左叶子。

        如果该节点的左节点不为空,该节点的左节点的左节点为空,该节点的左节点的右节点为空,则找到了一个左叶子,判断代码如下

if node.Left != nil && node.Left.Left == nil && node.Left.Right == nil {
    找到了一个左叶子节点;
    左叶子节点处理逻辑;
}

递归法:

        递归的遍历顺序为后序遍历(左右中),是因为要通过递归函数的返回值来累加求取左叶子数值之和

递归三部曲:

1、确定递归函数的参数和返回值

        判断一个树的左叶子节点之和,那么一定要传入树的根节点,递归函数的返回值为数值之和,所以int使用题目中给出的函数就可以了。

2、确定终止条件

if root == nil{
    return 0
}

3、确定单层递归的逻辑

        当遇到左叶子节点的时候,记录数值,然后通过递归求取左子树左叶子之和,和 右子树左叶子之和,相加便是整个树的左叶子之和。

       

func sumOfLeftLeaves(root *TreeNode) int {
    var  res int
    findLeft(root,&res)
    return res
}
func findLeft(root *TreeNode,res *int){
    //重要代码
    if root.Left!=nil&&root.Left.Left==nil&&root.Left.Right==nil{
        *res=*res+root.Left.Val
    }
    if root.Left!=nil{
        findLeft(root.Left,res)
    }
    if root.Right!=nil{
        findLeft(root.Right,res)
    }
}

今天脑壳有点懵。再来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值