LeetCode算法 | Day20 二叉树:最大二叉树、合并二叉树、二叉搜索树中的搜索、验证二叉搜索树

654. 最大二叉树

题目:

给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:

  1. 创建一个根节点,其值为 nums 中的最大值。
  2. 递归地在最大值 左边 的 子数组前缀上 构建左子树。
  3. 递归地在最大值 右边 的 子数组后缀上 构建右子树。
    返回 nums 构建的 最大二叉树 。
    示例:


输入:nums = [3,2,1,6,0,5]
输出:[6,3,5,null,2,0,null,null,1]
解释:递归调用如下所示:
- [3,2,1,6,0,5] 中的最大值是 6 ,左边部分是 [3,2,1] ,右边部分是 [0,5] 。
    - [3,2,1] 中的最大值是 3 ,左边部分是 [] ,右边部分是 [2,1] 。
        - 空数组,无子节点。
        - [2,1] 中的最大值是 2 ,左边部分是 [] ,右边部分是 [1] 。
            - 空数组,无子节点。
            - 只有一个元素,所以子节点是一个值为 1 的节点。
    - [0,5] 中的最大值是 5 ,左边部分是 [0] ,右边部分是 [] 。
        - 只有一个元素,所以子节点是一个值为 0 的节点。
        - 空数组,无子节点。

解题思路:

构造树一般采用的是前序遍历,递归三部曲如下:

  1. 确定递归函数的参数和返回值:参数传入的是存放元素的数组,两个下标。返回该数组构造的二叉树的头结点。
  2. 确定终止条件:
  • 如果 right - left < 1 就说明此时已经为null。
  • 如果 right - left === 1 就说明是叶子节点。
  1. 确定单层递归的逻辑:
  • 先要找到数组中最大的值和对应的下标, 最大的值构造根节点,下标用来下一步分割数组。
  • 最大值所在的下标左区间构造左子树。
  • 最大值所在的下标右区间构造右子树。
var constructMaximumBinaryTree = function (nums) {
    const traversal = (nums, left, right) => {
        if (right - left < 1) {
            return null;
        }
        if (right - left === 1) {
            return new TreeNode(nums[left]);
        }
        let maxIndex = left;
        let maxVal = nums[maxIndex];
        for (let i = left + 1; i < right; i++) {
            if (nums[i] > maxVal) {
                maxVal = nums[i];
                maxIndex = i;
            }
        }
        const root = new TreeNode(maxVal);
        root.left = traversal(nums, left, maxIndex);
        root.right = traversal(nums, maxIndex + 1, right);
        return root;
    }
    return traversal(nums, 0, nums.length);
};

617. 合并二叉树

题目:

给你两棵二叉树: root1 和 root2 。
想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
返回合并后的二叉树。
注意: 合并过程必须从两个树的根节点开始。
示例:


输入:root1 = [1,3,2,5], root2 = [2,1,3,null,4,null,7]
输出:[3,4,5,5,4,null,7]

解题思路:

遍历两棵树是同步进行的。注意这里既可以是新使用一个节点也可以在原来基础上进行加和操作。

var mergeTrees = function (root1, root2) {
    if (root1 === null) {
        return root2;
    }
    if (root2 === null) {
        return root1;
    }
    const root = new TreeNode(root1.val + root2.val);
    root.left = mergeTrees(root1.left, root2.left);
    root.right = mergeTrees(root1.right, root2.right);
    return root;
};

700. 二叉搜索树中的搜索

题目:

给定二叉搜索树(BST)的根节点 root 和一个整数值 val。
你需要在 BST 中找到节点值等于 val 的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 null 。
示例:


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

解题思路:

利用二叉搜索树的特性,即可解决:

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值。
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。
  • 它的左、右子树也分别为二叉搜索树。

1. 迭代法

var searchBST = function (root, val) {
    while (root !== null) {
        if (val < root.val) {
            root = root.left;
        } else if (val > root.val) {
            root = root.right;
        } else {
            return root;
        }
    }
    return null;
};

2. 递归法

var searchBST = function (root, val) {
    if (root === null || root.val === val) {
        return root;
    }
    let result = null;
    if (val < root.val) {
        result = searchBST(root.left, val);
    }
    if (val > root.val) {
        result = searchBST(root.right, val);
    }
    return result;
};

98. 验证二叉搜索树

题目:

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例:


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

解题思路:

1. 辅助数组

二叉搜索树中序遍历的结果是递增的。

var isValidBST = function (root) {
    const arr = [];
    const isValid = (root) => {
        if (root === null) {
            return;
        }
        isValid(root.left);
        arr.push(root.val);
        isValid(root.right);
    }
    isValid(root);
    for (let i = 0; i < arr.length; i++) {
        if (arr[i + 1] <= arr[i]) {
            return false;
        }
    }
    return true;
};

2. 利用最大值来判断

中序遍历的值始终都应该是最大值。

var isValidBST = function (root) {
    let maxVal = -Infinity;
    const isValid = (root) => {
        if (root === null) {
            return true;
        }
        const left = isValid(root.left);
        if (root.val > maxVal) {
            maxVal = root.val;
        } else {
            return false;
        }
        const right = isValid(root.right);
        return left && right;
    }
    return isValid(root);
};

3. 双指针

利用两个指针后一个比前一个大的原理来做。

var isValidBST = function (root) {
    let pre = null;
    const isValid = (root) => {
        if (root === null) {
            return true;
        }
        const left = isValid(root.left);
        if (pre!==null && pre.val >= root.val) {
           return false
        } 
        pre = root;
        const right = isValid(root.right);
        return left && right;
    }
    return isValid(root);
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容