LeetCode题解:使用区间分治策略构建二叉树

本文介绍了如何利用区间分治策略解决LeetCode上的两道题目,涉及将有序数组转换为高度平衡二叉搜索树以及根据前序与中序遍历序列构造二叉树。通过理解升序排列的特性,可以巧妙地进行区间划分并递归构造子树,从而避免复杂的旋转操作。

博客链接:Cs XJH’s Blog
今天在力扣上刷到两道法相似的题目,都是使用区间分治然后递归构造树的解决方法,感觉新有所得,于是决定记录下来。

LeetCode:将有序数组转换为二叉搜索树

题目描述

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例

给定有序数组: [-10,-3,0,5,9],

一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

看到平衡二叉搜索树——任意根结点的值大于等于左子树的所有结点的值,而小于右子树所有结点的值,并且任意结点的左右子树高度差不超过1。挠挠头,什么左旋右旋的,不会写呀,吓得我有赶紧拿出数据结构老师PPT来复习下的冲动。

但心里琢磨着,不应该这么复杂呀,于是去评论区看了下(菜鸟操作,请勿模仿),立刻就get到这到题的精髓了,原来关键在于升序这个字眼。因为数组元素是升序的,所以数组中间元素每次将会作为根结点的值,而两边的元素序列则用来构造左右子树。这种将数组划分区间并分开治理的方法叫做区间分治。

另外,这里我还学习到区间分治采用左闭右闭的区间端点选取策略,以及(left + right)/ 2的中间计算方法容易出现数值溢出情况,即left + right的值超过int最大值,所以中间值计算方法推荐使用left + (right - left) / 2

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        if (nums == null || nums.length == 0) {
            return null;
        }

        return build(nums, 0, nums.length-1); // 区间分治:左闭右闭
    }

    private TreeNode build(int[] nums, int l, int r) {
        if (l > r) {
            return null;
        }

        int m = l + (r - l) / 2; // (l + r)的值可能会大于int的最大值,即溢出
        TreeNode root = new TreeNode(nums[m]);
        root.left = build(nums, l, m-1);
        root.right = build(nums, m+1, r);

        return root;
    }
}

LeetCode:从前序与中序遍历序列构造二叉树

题目描述

根据一棵树的前序遍历与中序遍历构造二叉树。

示例

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7

这题之前在牛客上做过一次,但是现在做的时候又是一脸懵。唯一确定步骤是,先从前序遍历中拿到根结点,然后根据中序遍历得到左右子树。但是具体怎么实现呢!!!

心想,这无非又是递归实现,在递归过程中,将大问题不断的简化成小问题,就像求斐波那契数列一样。看到参数是两个数组,又联想到上一题的区间分治策略,于是思路立刻来了。模仿一下上一题的代码,一次就AC了。真开心,或许这就是学习和成长吧。

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder == null || preorder.length == 0) {
            return null;
        }

        return build(preorder, 0, preorder.length-1, inorder, 0, inorder.length);
    }

    private TreeNode build(int[] pre, int l1, int r1, int[] in, int l2, int r2) {
        if (l1 > r1 || l2 > r2) {
            return null;
        }

        int rootIndex = 0;

        TreeNode root = new TreeNode(pre[l1]);
        for (int i=l2; i<=r2; i++) {
            if (pre[l1] == in[i]) {
                rootIndex = i; 
                break;
            }
        }

        root.left = build(pre, l1+1, l1+rootIndex-l2, in, l2, rootIndex-1);
        root.right = build(pre, l1+rootIndex-l2+1, r1, in, rootIndex+1, r2);

        return root;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值