代码随想录算法训练营第二十一天 | 530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先

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

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

解题思路🤔

遇到在二叉搜索树上求最值、差值之类,把它想成在一个有序数组上求最值,求差值。

本题中,二叉搜索树采用中序遍历,其实就是一个有序数组。就转化为在一个有序数组上求两个数最小差值。

因此,思路为将二叉搜索树转换成有序数组,然后遍历一遍数组,就统计出来最小差值了。

遇到的问题😢

代码实现👨🏻‍💻

递归法

var getMinimumDifference = function (root) {

    let arr = [];
    
    const buildArr = (root) => {
        if (root) {
            buildArr(root.left);
            arr.push(root.val);
            buildArr(root.right);
        }
    }
    
    buildArr(root);
    let diff = arr[arr.length - 1];
    
    for (let i = 1; i < arr.length; ++i) {
        if (diff > arr[i] - arr[i - 1]) diff = arr[i] - arr[i - 1];
    }
    
    return diff;
};

总结📖


LeetCode 501.二叉搜索树中的众数

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

解题思路🤔

二叉搜索树中序遍历是有序的,从头遍历有序数组的元素出现频率,就是比较相邻两个元素,输出频率最高的元素。

比较相邻两个元素:设置一个指针cur指向当前节点,初始化一个指针pre = null,指向前一个节点。

找到频率最高的元素:代码如下:频率count大于 maxCount的时候,更新maxCount,同时清空结果集(result数组),因为结果集之前的元素都失效了。

遇到的问题😢

代码实现👨🏻‍💻

迭代法

var findMode = function(root) {
    // 使用中序遍历, 设置出现最大次数初始值为1
    let count = 0, maxCount = 1;
    let pre = root, res = [];
    
    // 1.确定递归函数及函数参数
    const travelTree = function(cur) {
    
        // 2. 确定递归终止条件
        if(cur === null) return ;
        travelTree(cur.left);
        
        // 3. 单层递归逻辑
        if(pre.val === cur.val) count++;
        else count = 1;
        pre = cur;
        
        if(count === maxCount) res.push(cur.val);
        
        if(count > maxCount) {
            res = [];
            maxCount = count;
            res.push(cur.val);
        }
        travelTree(cur.right);
    }
    
    travelTree(root);
    return res;
};

总结📖


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

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

解题思路🤔

找到公共祖先:二叉树自底向上查找 —> 回溯 —> 后序遍历(左右中)

  • 判断节点是节点q、p的公共祖先:
  1. 找到一个节点,发现左子树出现节点p,右子树出现节点q,或者 左子树出现结点q,右子树出现节点p,那么该节点就是节点p和q的最近公共祖先。

    • 此时如果递归遍历遇到q,就将q返回,遇到p就将p返回,如果左右子树的返回值都不为空,说明此时的中节点,一定是q和p 的最近祖先。
      ![在这里插入图片描述](https://img-blog.csdnimg.cn/806cfaac63aa4a459bd69904291f75a4.png在这里插入图片描述
  2. 节点本身p( q ),它拥有一个子孙节点q ( p )

    • 此时如果递归遍历遇到q,就将q返回,遇到p就将p返回,如果左右子树的返回值都不为空,说明此时的中节点,一定是q和p 的最近祖先。
      在这里插入图片描述
  • 递归三部曲:
  1. 确定递归函数的返回值和参数
    • 返回值:返回值不为空,说明找到了p、q
    • 参数:
  2. 确定终止条件
    • root == q,或者 root == p,说明找到 q p ,则将其返回
    • 如果遇到空,返回空
  3. 确定单层递归的逻辑
    在递归函数有返回值的情况下:
    • 如果要搜索一条边,递归函数返回值不为空的时候,立刻返回
    • 如果搜索整个树,直接用一个变量leftright接住返回值,这个leftright后续还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)。
    • 如果leftright都不为空,说明此时root就是最近公共节点。
    • 如果left为空,right不为空,就返回right,说明目标节点是通过right返回的,反之依然。
    • 如果leftright都为空,则返回left或者right都是可以的,也就是返回空。
  • 完整流程图:

在这里插入图片描述

遇到的问题😢

代码实现👨🏻‍💻

递归法

var lowestCommonAncestor = function(root, p, q) {
    // 使用递归的方法
    // 需要从下到上,所以使用后序遍历
    
    // 1. 确定递归的函数
    const travelTree = function(root, p, q) {
    
        // 2. 确定递归终止条件
        if(root === null || root === p || root === q) return root;
        
        // 3. 确定递归单层逻辑
        let left = travelTree(root.left, p, q);
        let right = travelTree(root.right, p, q);
        
        if(left !== null && right !== null) return root;
        
        if(left === null) return right;
        
        return left;
    }
    
   return travelTree(root, p, q);
};

总结📖

递归法

  1. 求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式。
  2. 在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
  3. 要理解如果返回值left为空,right不为空为什么要返回right,为什么可以用返回right传给上一层结果。

今日收获

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值