【代码训练营】day19 | 654.最大二叉树 & 617.合并二叉树 & 700.二叉搜索树中的搜索 & 98.验证二叉搜索树

所用代码 java

最大二叉树 LeetCode 654

题目链接:最大二叉树 LeetCode 654 - 中等

思路

感觉和昨天构建二叉树的题目一样,按我的思路有如下步骤:

  1. 数组长度为0,则直接返回null
  2. 找到数组中最大的值
  3. 以此值切割左子树右子树
  4. 左右子树递归返回根结点
class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return traversal(nums);
    }public TreeNode traversal(int[] nums){
        if (nums.length == 0) return null;
        // 找到根结点(最大值) 与索引
        int rootValue = Integer.MIN_VALUE;
        int index = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] > rootValue){
                rootValue = nums[i];
                index = i;
            }
        }
        // 构建根结点
        TreeNode root = new TreeNode(rootValue);
        // 提前返回 - 剪枝
        if (nums.length == 1) return root;// 切割左右区间
        int[] leftNums = Arrays.copyOfRange(nums, 0, index);
        int[] rightNums = Arrays.copyOfRange(nums, index + 1, nums.length);// 递归的构建左右子树
        root.left = traversal(leftNums);
        root.right = traversal(rightNums);return root;
    }
}

还有一种不用新建数组的做法,直接通过索引构建二叉树 – 左闭右开

class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return traversal(nums, 0, nums.length);
    }public TreeNode traversal(int[] nums, int begin, int end) {
        if (end - begin <= 0) return null;
        // 找到最大值与索引
        int rootValue = Integer.MIN_VALUE;
        int index = 0;
        for (int i = begin; i < end; i++) {
            if (nums[i] > rootValue) {
                rootValue = nums[i];
                index = i;
            }
        }
        // 构建二叉树的根
        TreeNode root = new TreeNode(rootValue);
        // 叶子结点返回
        if (end - begin == 1) return root;// 递归构建左右子树
        root.left = traversal(nums, begin, index);
        root.right = traversal(nums, index + 1, end);return root;
    }
}

总结

自从学会了从中序+前序(后序)构建二叉树,这种类似的题就感觉不难了,都是同样的方法,找到根结点之后切割数组,最后递归构建左右子树就好了。

合并二叉树 LeetCode 617

题目链接:合并二叉树 LeetCode 617 - 简单

思路

无。主要是一起操作两个二叉树,同时遍历

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        return merge(root1, root2);
    }public TreeNode merge(TreeNode root1, TreeNode root2){
        // root1是空结点,但是root2不是空结点的话,就把root2的结点给返回
        // 若同时为null,就第一个if返回null(root2==null)
        if (root1 == null) return root2;
        if (root2 == null) return root1;// 中 - 不是空结点的情况,就把值相加
        TreeNode root = new TreeNode();
        root.val = root1.val + root2.val;//左 root左子树接收左边返回的结果
        root.left = merge(root1.left, root2.left);
        //右 root右子树接收右边返回的结果
        root.right = merge(root1.right, root2.right);return root;
    }
}

可不用另外定义一个函数,我是因为习惯了,另外也可以不用新建一个二叉树,只需把原本传入的二叉树重新赋值就好了

// 中 
root1.val += root2.val; 
// 左
root1.left = merge(root1.left, root2.left);
// 右
root1.right = merge(root1.right, root2.right);

总结

习惯了递归时操作一个二叉树,对应同时操作两个二叉树还是不会,需要加强训练。

遍历tree1和tree的时候,时候同步进行遍历的,同时到达某一个子结点

二叉搜索树中的搜索 LeetCode 700

题目链接:二叉搜索树中的搜索 LeetCode 700 - 简单

思路

二叉搜索树是左子树小于根结点,右子树大于根结点,可以根据此特性在两端进行搜索。

递归

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        return serach(root, val);
    }public TreeNode serach(TreeNode node, int val){
        if (node == null) return null;
        if (node.val == val) return node;
        TreeNode res = null;
        if (val < node.val){
            res = serach(node.left, val);
        }
        if (val > node.val){
            res = serach(node.right, val);
        }
        return res;
    }
}

迭代

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        // 这里使用栈和队列是一样的
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode res = null;
        if (root != null) stack.push(root);
        while (!stack.isEmpty()){
            res = stack.pop();
            if (res.val == val) return res;
            else if (res.val < val && res.right != null) {
                stack.push(res.right);
            }
            else if (res.val > val && res.left != null) {
                stack.push(res.left);
            }
        }
        // 这里不能返回res,因为没有找到时res里还存着一个结点
        // 没找到直接返回null就行了
        return null;
    }
}

其实迭代可以不利用栈或队列存数据,代码将会更简洁

class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        while (root != null){
            // 直接利用二叉搜索树的特性,进行左右搜索就可以了
            if (root.val > val) root = root.left;
            else if (root.val < val) root = root.right;
            else return root;
        }
        return null;
    }
}

总结

第一次做二叉搜索类的题目,一开始还是想的和普通二叉树方法一样,但是没必要。我们直接利用二叉搜索树的特性,可以将代码写的很简短很漂亮。

验证二叉搜索树 LeetCode 98

题目链接:验证二叉搜索树 LeetCode 98 - 中等

思路

无。


我们要利用二叉搜索树的特性:二叉树中序遍历元素一定是有序的(单调递增)

null 是二叉搜索树

class Solution {
    public boolean isValidBST(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        inorder(root, list);
        for (int i = 0; i < list.size() - 1; i++) {
            // 二叉搜索树不能有相同的数值
            if (list.get(i) >= list.get(i+1)) return false;
        }
        return true;
    }public void inorder(TreeNode node, List<Integer> list){
        if (node == null) return;
        inorder(node.left, list);
        // 中
        list.add(node.val);
        inorder(node.right, list);
    }
}

根据上面的方法,可以得到一个更简单的,这个方法就不用额外的list去存二叉树里面的值

注意: 本题结点值的范围 -2^31 <= Node.val <= 2^31 - 1 所以不能用Integer.MIN_VALUE,因为node可能包含最小值了,所以要用long型。

class Solution {
    long pre = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        return inorder(root);
    }
    // 中序
    public boolean inorder(TreeNode node){
        if (node == null) return true;boolean left = inorder(node.left);
        // 中 - 只需要判断每次加入的数值是不是比前一个大就好了(二叉搜索树性质)
        if (node.val > pre){
            pre = node.val;
        }else return false;
        boolean right = inorder(node.right);return left && right;
    }
}

但是如果有更小的数呢?我们必须避免这种情况,所以用双指针的方式进行改进。

class Solution {
    TreeNode pre = null;
    public boolean isValidBST(TreeNode root) {
        return inorder(root);
    }
    // 中序
    public boolean inorder(TreeNode node){
        if (node == null) return true;boolean left = inorder(node.left);
        // 中 - 只需要判断每次加入的数值是不是比前一个大就好了(二叉搜索树性质)
        if (pre != null && pre.val >= node.val){
            return false;
        }
        // 当到第一个结点(最左边的叶子结点)时,不会进入if,直接把第一个结点赋值给pre
        // 再此递归时,已经到了叶子结点了父节点,而pre就是他的前一个结点
        pre = node;
        boolean right = inorder(node.right);return left && right;
    }
}

总结

本题必须要想到二叉搜索树的性质,不然就很难,特别是中序遍历出来的结果是单调递增这一点!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值