二叉树:530. 二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先

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


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

题目链接:530. 二叉搜索树的最小绝对差

💡解题思路

  1. 中序遍历后转数组:根据二叉搜索树的特性,中序遍历得到的数组,是一个有序递增的数组,所以可以先讲二叉树转化为数组,在进行相邻两项的值的差值判断
    • 递归法:三部曲
  • 确定递归函数,返回值以及参数:参数为二叉树
  • 确定终止条件:二叉搜索树也可以为空!
  • 确定单层递归的逻辑:中序遍历,定义一个指针preNode和一个无穷大的数res,指针指向当前节点的上一个节点,当该指针有值时,Math.min(res, node.val - preNode.val),指针移动,preNode = node

🤔遇到的问题

  1. 递归法定义的指针,是需要移动的,并且不能为空
  2. 迭代法流程不熟悉了,此处没有写

💻代码实现

转数组

var getMinimumDifference = function (root) {
    //中序遍历,将二叉树转成有序数组
    let arr = []
    const buildTree = (node) => {
        if (node) {
            buildTree(node.left)
            arr.push(node.val)
            buildTree(node.right)
        }
    }
    buildTree(root)
    //遍历数组,求相邻两项的最小差值
    let res = arr[1] - arr[0];
    for (let i = 1; i < arr.length; i++) {
        if (arr[i] > arr[i - 1]) {
            res = Math.min(res, arr[i] - arr[i - 1])
        }
    }
    return res
};

递归

var getMinimumDifference = function (root) {
    //定义一个无穷大的数
    let res = Infinity
    let preNode = null
    const inorder = (node) => {
        if (!node) return
        //左
        inorder(node.left)
        // 更新res
        //中
        if (preNode) {
            res = Math.min(res, node.val - preNode.val)
        }
        // 记录前一个节点
        preNode = node
        //右
        inorder(node.right)
    }
    inorder(root)
    return res
};

🎯题目总结

遇到在二叉搜索树上求什么最值,求差值之类的,都要思考一下二叉搜索树可是有序的,要利用好这一特点
在递归遍历的过程中如何记录前后两个指针,这也是一个小技巧
在这里插入图片描述

501.二叉搜索树中的众数

题目链接:501.二叉搜索树中的众数

💡解题思路

  1. 普通二叉树的解法:把这个树都遍历了,用map统计频率,把频率排个序,最后取前面高频的元素的集合,具体操作如下:
  • 这个树都遍历了,用map统计频率,key:节点值;value:节点值出现的次数
  • 定义一个最大出现次数的初始值为root.val的出现次数
  • 遍历map,当前值value等于最大出现次数就直接在res增加该key;如果value的值大于原本的maxCount就清空res的所有值,将此时value对应的key放入res中
  1. 二叉搜索树的解法:既然是搜索树,它中序遍历就是有序的,使用了pre指针和cur指针,具体操作如下:
  • 定义count:当前节点出现的次数;定义maxCount:树中出现最多的次数;定义pre:存储当前节点的前一个节点;递归函数,参数传树的根节点
  • 确定递归终止条件 :node ===null 叶子节点时终止
  • 单层递归逻辑:重点在“中”,前一个节点与当前节点的比较,当两个节点的值相等时,count++,不相等,count=1;count与maxcount做比较,相等,则将node的值,存入res中,当count>maxCount时,maxCount的值更新,res清空,将node的值,存入res中,最后指针移动,保留前一个节点,pre= node

🤔遇到的问题

  1. map的遍历的时候,key与value的比较及获取出错
  2. 指针法遍历中的逻辑,不太熟练

💻代码实现

普通二叉树

var findMode = function (root) {
    //将数据存储到map中
    //key:节点值;value:出现的次数
    let map = new Map()
    const buildTree = (node) => {
        if (node) {
            buildTree(node.left)
            map.set(node.val, map.has(node.val) ? map.get(node.val) + 1 : 1)
            buildTree(node.right)
        }
    }
    buildTree(root)
     // 定义一个最大出现次数的初始值为root.val的出现次数
    let maxCount = map.get(root.val)
    // 定义一个存放结果的数组res
    let res = []
    for (let [key, value] of map) {
        // 如果当前值等于最大出现次数就直接在res增加该值
        if (value === maxCount) {
            res.push(key)
        } else if (value > maxCount) {
            // 如果value的值大于原本的maxCount就清空res的所有值,因为找到了更大的
            maxCount = value
            res = []
            res.push(key)
        }
    }
    return res
};

二叉搜索树

var findMode = function (root) {
    //当前节点的出现次数
    let count = 0
    //出现最大次数初始值为1
    let maxCount = 1
    let pre = root
    let res = []
    // 1.确定递归函数及函数参数
    const travelTree = (node) => {
         // 2. 确定递归终止条件  叶子节点
        if (node === null) return
        travelTree(node.left)
         // 3. 单层递归逻辑   中
        //当前节点与上一个节点的值相同
        if (pre.val === node.val) {
            count++
        } else {
            //不同的话,该节点的就是第一次出现
            count = 1
        }
        //该节点出现次数与最大次数比较,相同则将该节点值放入数组中
        if (count === maxCount) {
            res.push(node.val)
        } else if (count > maxCount) {
            //该节点出现次数比最大次数大,那么最大次数的值更新,res清空后,再把该节点值放入
            maxCount = count
            res = []
            res.push(node.val)
        }
        //指针移动,保留前一个节点
        pre =node
        travelTree(node.right)
    }
    travelTree(root)
    return res
    
};

🎯题目总结

二叉搜索树的所有遍历,都可以使用其特性进行,同时普通的二叉树,也有保守的方法可以解决该问题


236. 二叉树的最近公共祖先

题目链接:236. 二叉树的最近公共祖先

💡解题思路

  1. 查找公共祖先,需要自底向上查,二叉树回溯的过程就是从低到上,后序遍历(左右中)就是天然的回溯过程,可以根据左右子树的返回值,来处理中节点的逻辑。
  2. 如何判断一个节点是节点q和节点p的公共祖先?
  • 如果递归遍历遇到q,就将q返回,遇到p 就将p返回,那么如果 左右子树的返回值都不为空,说明此时的中节点,一定是q 和p 的最近祖先在这里插入图片描述
  • 就是节点本身p(q),它拥有一个子孙节点q§,遇到 q 或者 p 就返回,这样也包含了 q 或者 p 本身就是 公共祖先的情况在这里插入图片描述
  1. 递归三部曲:
  • 确定递归函数返回值以及参数:需要递归函数返回值,来告诉我们是否找到节点q或者p;参数就是根节点及p、q
  • 确定终止条件:遇到空的话,因为树都是空了,所以返回空;如果 root == q,或者 root == p,说明找到 q p ,则将其返回
  • 确定单层递归逻辑: 本题函数有返回值,是因为回溯的过程需要递归函数的返回值做判断,遍历左右子树,拿遍历后的结果处理中间节点,如果left 和 right都不为空,说明此时root就是最近公共节点如果left为空,right不为空,就返回right,说明目标节点是通过right返回的,反之依然如果left和right都为空,则返回left或者right都是可以的,也就是返回空在这里插入图片描述

🤔遇到的问题

  1. 搜索一条边还是搜索一棵树的问题

💻代码实现

递归法

var lowestCommonAncestor = function(root, p, q) {
    const travelTree = (node, p, q)=>{
        if (node === null || node === p || node === q) return node
        let left = travelTree(node.left, p, q)
        let right = travelTree(node.right, p, q)
         若找到两个节点
        if (left !== null && right !== null) return node
         若找到一个节点
        // if (left !== null && right === null) return left
        // if (left === null && right !== null) return right
        //没有找到节点
        // if (left === null && right === null) return null
        //可简化
        if(left === null) {
            return right;
        }
        return left;
    }
    return travelTree(root,p,q)
};

🎯题目总结

1、求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式
2、在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断
3、要理解如果返回值left为空,right不为空为什么要返回right,为什么可以用返回right传给上一层结果
4、递归函数又返回值的情况,如何是搜索一条边,如何是搜索一棵树?
如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)

🎈今日心得

二叉树的最近祖先这道题,确实难,也不好理解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值