二叉树:513.找树左下角的值、112. 路径总和、106.从中序与后序遍历序列构造二叉树

提示:努力生活,开心、快乐的一天


513.找树左下角的值

题目链接:513.找树左下角的值

💡解题思路

  1. 首先明确一个概念:树的最后一行找到最左边的值,可能是左节点,也可能是右节点
  2. 递归法:三部曲
  • 确定递归函数的参数和返回值:要遍历的树的根节点、当前节点的深度、记录最大深度、记录最大深度最左节点的数值
  • 确定终止条件:当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度
  • 确定单层递归的逻辑:遍历左右子树、不需要中
  1. 迭代法:只需要记录最后一行第一个节点的数值就可以了

🤔遇到的问题

  1. 迭代法记录数值遇到了问题
  2. 递归法不需要遍历中

💻代码实现

递归法

var findBottomLeftValue = function(root) {
  //首先考虑递归遍历 前序遍历 找到最大深度的叶子节点即可
  //最大深度
  let maxPath = 0
  //最大深度对应的节点值
  let resNode = null
  // 1. 确定递归函数的函数参数
  //树的根节点及节点当前深度
  const getDfs = (node,curPath)=>{
    // 2. 确定递归函数终止条件
    //该节点给叶子结点
    if(node.left===null&&node.right===null){
      if(curPath>maxPath){
        maxPath = curPath
        resNode = node.val
      }
    }
     //单层逻辑,左右
    node.left && getDfs(node.left,curPath+1)
    node.right && getDfs(node.right,curPath+1)
  }
  getDfs(root,1)
  return resNode
};

迭代法

var search = function (nums, target) {
var findBottomLeftValue = function(root) {
  //最大深度对应的节点值
  let resNode = null
  if(!root) return null
  let queue = []
  queue.push(root)
  while(queue.length){
    let len = queue.length
    for(let i=0;i<len;i++){
      let node = queue.shift()
      if(i===0){
        resNode = node.val
      }
      node.left&&queue.push(node.left)
      node.right&&queue.push(node.right)
    }
  }
  return resNode
};

🎯题目总结

  1. 明确树的最后一行找到最左边的值,可能是左节点,也可能是右节点
  2. 递归法找到终止便利的条件即可
  3. 迭代法非常的方便,只需记录每一层的第一个值即可

112. 路径总和

题目链接:112. 路径总和

💡解题思路

  1. 递归法:三部曲
  • 确定递归函数的参数和返回类型:需要二叉树的根节点,还需要一个计数器,这个计数器用来计算二叉树的一条边之和是否正好是目标和
  • 确定终止条件:不要去累加然后判断是否等于目标和,那么代码比较麻烦,可以用递减,让计数器count初始为目标和,然后每次减去遍历路径节点上的数值。如果最后count == 0,同时到了叶子节点的话,说明找到了目标和。如果遍历到了叶子节点,count不为0,就是没找到。
  • 确定单层递归的逻辑:因为终止条件是判断叶子节点,所以递归的过程中就不要让空节点进入递归了。递归函数是有返回值的,如果递归函数返回true,说明找到了合适的路径,应该立刻返回。
  1. 迭代法:栈里一个元素不仅要记录该节点指针,还要记录从头结点到该节点的路径数值总和
    在这里插入图片描述

🤔遇到的问题

  • 递归法需要注意,递归是有返回值的
  • 迭代法:从头结点到该节点的路径数值总和相加忘记计算了

💻代码实现

递归法

var hasPathSum = function(root, targetSum) {
  if(!root) return false
  const traversal = (node,cursum)=>{
    // 遇到叶子节点,并且计数为0
    if(!node.left&&!node.right&&cursum===0) return true
     // 遇到叶子节点而没有找到合适的边(计数不为0),直接返回
    if(!node.left&&!node.right&&cursum!==0) return false
    //  左(空节点不遍历).遇到叶子节点返回true,说明其叶子结点满足条件,则直接返回true
    if(node.left&&traversal(node.left,cursum-node.left.val)) return true
    //  右(空节点不遍历)
    if(node.right&&traversal(node.right,cursum-node.right.val)) return true
    return false
  }
  return traversal(root,targetSum-root.val)
};

迭代法

var hasPathSum = function(root, targetSum) {
  if(!root) return false
  let nodeArr = [root]
  let valArr = [0]
  while(nodeArr.length){
    //当前节点的指针
    let curNode = nodeArr.shift()
    //从头结点到该节点的路径数值总和
    let curVal = valArr.shift()
    curVal += curNode.val;
    // 为叶子结点,且和等于目标数,返回true
    if(!curNode.left&&!curNode.right&&curVal===targetSum){
      return true
    }
    // 左节点,将当前的数值也对应记录下来
    if(curNode.left){
      nodeArr.push(curNode.left)
      valArr.push(curVal)
    }
    // 右节点,将当前的数值也对应记录下来
    if(curNode.right){
      nodeArr.push(curNode.right)
      valArr.push(curVal)
    }
  }
  return false
};

🎯题目总结

递归函数什么时候需要返回值?什么时候不需要返回值?这里总结如下三点:

  • 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是113.路径总和ii)
  • 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。(这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
  • 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)

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

题目链接:106.从中序与后序遍历序列构造二叉树

💡解题思路

  1. 如果数组大小为零的话,说明是空节点了
  2. 如果不为空,那么取后序数组最后一个元素作为节点元素。
  3. 找到后序数组最后一个元素在中序数组的位置,作为切割点
  4. 切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
  5. 切割后序数组,切成后序左数组和后序右数组
  6. 递归处理左区间和右区间
    在这里插入图片描述
    此时有一个很重的点,就是中序数组大小一定是和后序数组的大小相同的(这是必然)

🤔遇到的问题

  • 在进行切割的时候,边界没有处理好

💻代码实现

递归法

var buildTree = function(inorder, postorder) {
    if(!inorder.length) return null
    //从后续中获取根节点
    let rootVal = postorder.pop()
    //获取根节点在中序遍历中的位置
    let rootIndex = inorder.indexOf(rootVal)
    let root = new TreeNode(rootVal)
    //分割中序遍历的左右子树 
    let leftInTree = inorder.slice(0,rootIndex)
    let rightInTree = inorder.slice(rootIndex+1)
    //分割后续遍历的左右子树
    let leftPosTree = postorder.slice(0,rootIndex)
    let rightPosTree = postorder.slice(rootIndex)
    //递归处理左区间和右区间
    root.left = buildTree(leftInTree,leftPosTree)
    root.right = buildTree(rightInTree,rightPosTree)
    return root
};

🎯题目总结

前序和中序可以唯一确定一棵二叉树。
后序和中序可以唯一确定一棵二叉树。
前序和后序不能唯一确定一棵二叉树!

🎈今日心得

还不错,只是拓展的题目因为思路一样,所以没有记录博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值