Day 17 二叉树part05

654. 最大二叉树

这道题和昨天的根据中序后序遍历构造二叉树比较相似。借鉴那个思路去做就差不多。

class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return construct(nums, 0, nums.length);
    }

    public TreeNode construct(int[] nums, int left, int right){ //左闭右开,递归去解决时也注意这一点
        if(left >= right) return null;
        int ind = -1, max = -1;
        for(int i = left; i < right; i++){
            if(nums[i] > max){ //找到最大值所在位置,使用这个值将原nums数据进行划分,递归的去解决左右子树
                max = nums[i];
                ind = i;
            }
        }
        TreeNode left_ = construct(nums, left, ind);
        TreeNode right_ = construct(nums, ind + 1, right);
        return new TreeNode(nums[ind], left_, right_);
    }
}

617. 合并二叉树

这种套路还是很重要的,就是同时去遍历两个树,可以和101. 对称二叉树这道题比较着看,都是需要去处理两个树上对应位置的节点。

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if(root1 == null) return root2;
        if(root2 == null) return root1;
        root1.val += root2.val;
        root1.left = mergeTrees(root1.left, root2.left);
        root1.right = mergeTrees(root1.right, root2.right);
        return root1;
    }
}

700. 二叉搜索树中的搜索

这道题很简单,不管是用迭代去做还是递归。最主要的还是明白二叉搜索树的定义就好了。

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        TreeNode tmp = root;
        while(tmp != null){
            if(tmp.val == val) return tmp;
            if(tmp.val > val) tmp = tmp.left;
            else tmp = tmp.right;
        }
        return null;
    }
}

98. 验证二叉搜索树

通过这道题真的是对二叉树的前中后序遍历又有了新的理解,很好的一道题目。这个题解非常好很易懂(除了后序遍历)。

首先是前序遍历的方法,这里就是需要先对当前节点是否合法做出判断,我们可以新创建一个函数用于判断节点是否合法,我们知道对于搜索树的每个位置,都对应一个准确的区间,一个节点的左子树一定小于当前节点的值,同理右子树大于该值。对于根节点,其取值范围可以是从负无穷到正无穷(不同的语言有不同的实现方法,对于本题使用java可以用Long.MIN_VALUE MAX_VALUE),对于其左子树,其取值范围为(负无穷,root.val),右子树(root.val, 正无穷),如此反复,对于每个节点都可以确定一个区间,因此,只需要判断区间是否合法以及左右子树是否都合法即可。

class Solution {
    public boolean isValidBST(TreeNode root) {
        return _isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    public boolean _isValidBST(TreeNode root, long left, long right){
        if(root == null) return true;
        return root.val > left && root.val < right && 
         _isValidBST(root.left, left, root.val) && _isValidBST(root.right, root.val, right);
    }
}

中序遍历的版本,对于二叉搜索树,其中序遍历一定是递增的,因此对二叉搜索树进行中序遍历,然后用pre记录上一个节点val,满足严格递增才是true。

class Solution {
    long pre = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        if(root == null) return true;
        boolean isLeftValid = isValidBST(root.left);
        if(root.val <= pre) return false;
        pre = root.val;
        boolean isRightValid = isValidBST(root.right);
        return isLeftValid && isRightValid;
    }
}

后序遍历,看的不是很懂,主要还是对于非法值的处理看不明白。这里先贴上代码,把我目前理解的部分先用注释了。我个人觉得这里最难理解的地方就是(-inf, inf)和(inf, -inf)的含义是什么,以及是怎么想到这样的取值范围的。目前我只能理解到这样做可以work。

class Solution {
    Long inf = Long.MAX_VALUE, n_inf = Long.MIN_VALUE; //由于node val可能出现int的最大最小值,使用long中最大最小值作为正负无穷
    public boolean isValidBST(TreeNode root) {
        return boundary(root)[1] != inf;
    }
    public long[] boundary(TreeNode root){
        if(root == null) return new long[]{inf, n_inf}; //不能理解怎么想到这种奇怪的做法的,这样做可以使得叶子节点的取值范围正确,比如有个叶子节点val为1,那么该函数执行后,返回值为[1, 1]
        long[] left = boundary(root.left);
        long[] right = boundary(root.right);
        if(root.val >= right[0] || root.val <= left[1]) //节点非法
            return new long[]{n_inf, inf}; //如果有一个节点非法,可以看出,后面需要这个返回值的一系列执行结果都是非法的,即如果有一个节点的取值范围为(-inf, inf)那么他的所有父亲节点取值范围都为(-inf, inf)。
        return new long[]{Math.min(left[0], root.val), Math.max(right[1], root.val)};
    }
}
posted @ 2024-07-19 18:16  12点不睡觉还想干啥?  阅读(21)  评论(0)    收藏  举报