java算法day18

java算法day18

  • 617 合并二叉树
  • 700 二叉搜索树中的搜索
  • 98 验证二叉搜索树

617 合并二叉树

正如题目所说,那么看起来这个题就是两个树同时做递归左右子树,然后在这个过程中做合并,构建树。并且从上到下处理,那么就是先序遍历。

构建树可以有两种做法。
法1:每层新new一个节点,在归的过程中建立联系。
昨天在后序和中序遍历构建二叉树中学到了一种构建树的新方法,每层都new一个新节点,然后对其左右子树进行递归,在返回的时候建立节点与节点之间的联系,所以返回值就是该层构建好的节点,由于是归的过程建立的联系,那么归到某一层的时候,该层返回的节点,他的下面的结构都是已经构造好了。

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        // 如果两个节点都为空,返回null
        if (root1 == null && root2 == null) {
            return null;
        }
        
        // 计算新节点的值
        int value = 0;
        if (root1 != null) {
            value += root1.val;
        }
        if (root2 != null) {
            value += root2.val;
        }
        
        // 创建新节点
        TreeNode newNode = new TreeNode(value);
        
        // 递归处理左子树
        if (root1 == null) {//必须传null,传root1.left就会空指针。点不出来的,下面同
            newNode.left = mergeTrees(null, root2.left);
        } else if (root2 == null) {
            newNode.left = mergeTrees(root1.left, null);
        } else {
            newNode.left = mergeTrees(root1.left, root2.left);
        }
        
        // 递归处理右子树
        if (root1 == null) {
            newNode.right = mergeTrees(null, root2.right);
        } else if (root2 == null) {
            newNode.right = mergeTrees(root1.right, null);
        } else {
            newNode.right = mergeTrees(root1.right, root2.right);
        }
        
        return newNode;
    }
}

该做法的缺点很明显,1.要写很多的if判断来走哪种递归方式,不分情况传就会空指针异常。
2.费空间,每一层都会new一个新的节点。


法2:原地构建
本质思路还是同时递归左右子树,只是处理过程有差别。本题是在root1上进行构建
这种方法就抓住一句话。
修改指针可以是很方便的方式
这个代码建议先看中间,然后再去想递归出口

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
    //由于是同时递归下去的,二者到下层时要先判断,有没有一方为空,想想如果有一方为空,另一方不为空,那么空的一方后面就已经没有节点了,此时直接返回非空的部分,不就是代表后面的内容全是这个非空的部分。而这里就是改个指针的功夫。后面也没必要走了。
    //看代码,这里如果root1是null那么后面就拼root2的部分。
    //如果root1不为null,那么检查root2,如果root2为null,那么后面的结果都是root1的,直接返回,后面不用再进行构建了。
    //而且如果都为null,这里就会返回null。只能说很妙。
        if (root1 == null) return root2;
        if (root2 == null) return root1;
        //两个节点进行合并
        root1.val += root2.val;
        //递归构建root1的左右子树
        root1.left = mergeTrees(root1.left, root2.left);
        root1.right = mergeTrees(root1.right, root2.right);
        //最后完成构建是在root1上,所以返回root1。这就是结果
        return root1;
    }
}

700 二叉搜索树中的搜索

依据二叉搜索树的性质,不断的调整往下的递归方向就可以做出来。
因为BST的性质,如果找不到就会一直往下搜,直到碰到null。找得到就停了。

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if(root==null){
            return null;
        }

        if(val<root.val){
            return searchBST(root.left,val);
        }else if(val>root.val){
            return searchBST(root.right,val);
        }else{
            return root;
        }

    }
}

98 验证二叉搜索树

验证二叉搜索树的核心思路:
要知道二叉搜索树的判定:节点从上到下递归满足左子树小于根节点,根节点小于右子树。

我一开始顺着这个思路做就想到了双重递归,从上到下的去验证每个节点是否满足这个定义,这个做法是非常不好的。一看就是有大量的冗余运算。

所以本题用的方法,我称之为范围限制和束缚传递。

具体做法:
1.为树中的每个节点定义一个有效值的范围,这个范围有一个下界和一个上界定义。
2.初始时根节点可以是任何值,其范围是正无穷和负无穷,那么此时就可以用MAX常量。

3.递归定义子节点的范围,对于任何节点,其左子节点的值必须小于该节点的值,单要大于该节点的下界。其右子节点的值必须大于该节点的值,并且小于该节点的上界。
4.递归的时候就要不断的更新范围,节点必须要在该范围内才能满足二叉搜索树的性质。
5.范围更新规则:递归左子树,上界变为当前节点的值,下届保持不变。
递归右子树,下届变为当前节点的值,上界保持不变。


懂了这些就可以总结快速做法

如果往左递归,可以把开区间的右边界更新为当前节点,如果往右递归,就把开区间的左边界更新为当前节点。
从这个图里可以看到,上层的约束,已经带到下层去了,而且这个范围在不断的收缩。
在这里插入图片描述
这个做法是先序遍历的做法,即从上到下

class Solution {
    public boolean isValidBST(TreeNode root) {
    //第一层就是root,然后范围为无穷大和无穷小,由于测试用例要求到Long了,那么就用Long的
        return isValidBST(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    private boolean isValidBST(TreeNode node, long left, long right) {
    //递归出口,到这里说明路上的元素都满足了
        if (node == null) {
            return true;
        }
        //把当前节点值拿出来做验证
        long x = node.val;
        //先序遍历的思想
        //不仅本层要满足,左右子树也要满足。所以就这样递归下去
        return left < x && x < right &&
               isValidBST(node.left, left, x) &&
               isValidBST(node.right, x, right);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值