• JS Leetcode 530. 二叉搜索树的最小绝对差 题解分析,再次了解中序遍历


    壹 ❀ 引

    本题来自LeetCode 783. 二叉搜索树节点最小距离,题目描述如下:

    给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。

    示例 1:

    输入:root = [4,2,6,1,3]
    输出:1
    

    示例 2:

    输入:root = [1,0,48,null,null,12,49]
    输出:1
    

    提示:

    树中节点数目在范围 [2, 100] 内
    0 <= Node.val <= 105
    差值是一个正数,其数值等于两值之差的绝对值

    贰 ❀ 题解分析

    也许当你看到此题,你会想着题目要求任意两个不同节点中找到最小差,应该怎么遍历才好呢。我们假定给你一个有序的数组[1,3,4,6],如果让你求最小差会怎么做?你一定会每次拿两个相邻的数进行求差,然后右移,一直找到最小的差集。

    为什么是相邻的两个数?因为数组既然有序了,不找相邻难道求两个相隔N个数的差吗?比如上面的数组3-1的差一定比4-1的小。

    所以暴力的做法,我们可以用递归的方式将二叉树转为数组,排序后依次遍历,并找出最小的差。虽然这样做可以,但其实没必要。

    让我们再回头看一眼例子中的二叉树,你会发现每个左子树的节点,一定比父节点小,然后父节点又比右子树的节点小。

    比如图1中,1<2<3,而3有可以看成是4的左子树,且2<4<5,哎?如果我们按照这个顺序去遍历,就不用生成数组还做排序了,因为这个过程就是有序的,那么这个查找过程其实就是中序遍历了。我在JS 前序遍历、中序遍历、后序遍历、层序遍历详解,深度优先与广度优先区别,附leetcode例题题解答案一文中介绍了前序遍历,中序遍历以及后续遍历的基本模板与遍历过程,有兴趣的同学可以看看。

    那么我们直接贴上中序遍历的模板:

    var inorderTraversal = function(root) {
        // 遍历函数
        function traversal(root) {
            if (root !== null) {
                if (root.left) {
                    // 递归遍历左子树
                    traversal(root.left);
                };
                // 访问根节点的值
                console.log(root.val)
                if (root.right) {
                    // 递归遍历右子树
                    traversal(root.right);
                };
            };
        };
        traversal(root);
    };
    

    因为中序遍历满足左节点------>根节点------>右节点的顺序,所以如果一个根节点有左节点,那就先访问左节点,而左节点可能还有自己的左节点,所以递归一直往下找,直到找不到了,这个时候我们就可以处理我们想要的逻辑了,比如打印出此时节点的值。

    我们知道,函数调用栈是先进后出,当左节点的函数执行完成被释放,那自然下一个执行的就是自己的根节点的函数了,根节点函数执行完被释放,自然又会执行右节点的函数....一直执行,知道整个二叉树的节点被访问完毕。

    那么我们就可以利用中序遍历的特点,在访问每个节点的时候,求跟上一个节点的差值,并存起来,然后依次比较,注意,我们要存2个东西,一个是上一个节点的值,这个值在递归时是不断被更新的,第二个是最小值,如果遇到更小就更新它即可。

    综合上面的想法,让我们来实现它:

    /**
     * Definition for a binary tree node.
     * function TreeNode(val) {
     *     this.val = val;
     *     this.left = this.right = null;
     * }
     */
    /**
     * @param {TreeNode} root
     * @return {number}
     */
    var getMinimumDifference = function (root) {
        function findMin(node) {
            if (node === null) {
                return;
            };
            if (node.left) {
                findMin(node.left);
            };
            // 这里是为了避免第一个节点参与比较
            if (pre !== null) {
              	// abs用于消除差为负数的情况,直接比较绝对值
                min = Math.min(min, Math.abs(node.val - pre));
            };
            pre = node.val;
            if (node.right) {
                findMin(node.right);
            };
        };
        // 第一个节点因为找不到更前面的节点了,所以故意设置个null用于消除第一次比较
        let pre = null, min = Infinity;
        findMin(root);
        return min;
    };
    

    唯一需要注意的是是初始pre是null,目的是第一个左节点找不到其它节点进行求差,准确来说应该是从第二个节点开始才能求出差,所以设为null就是这个目的,其它就没什么难度了,那么本文结束。

  • 相关阅读:
    网络分析(二)定向与非定向
    Flex 找不到html文件,不能自动生成html问题解决
    常用的功能点记录
    git常规操作命令整理
    语境驱动测试7原则
    探索式测试的问与答
    测试建模:Google ACC
    探索式测试:基于测程的测试管理(SessionBased Test Management)
    用Excel展示SQL Server中的数据 (III): IronPython与自动化
    在Ajax中使用Flash实现跨域数据读取
  • 原文地址:https://www.cnblogs.com/echolun/p/14669263.html
Copyright © 2020-2023  润新知