代码随想录算法训练营第二十天 | 最大二叉树、合并二叉树、二叉搜索树中的搜索、验证二叉搜索树

目录

  • 最大二叉树
  • 合并二叉树
  • 二叉搜索树中的搜索
  • 验证二叉搜索树

LeetCode 654.最大二叉树
LeetCode 617.合并二叉树
LeetCode 700.二叉搜索树中的搜索
LeetCode 98.验证二叉搜索树

最大二叉树

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

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

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {

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

    public TreeNode construct(int[] nums, int begin, int end) {
        if (begin >= end) return null;
        int maxIndex = begin;// 最大值所在位置
        int maxValue = nums[maxIndex];// 最大值
        for (int i = begin + 1; i < end; i++) {
            if (nums[i] > maxValue){
                maxValue = nums[i];
                maxIndex = i;
            }
        }
        TreeNode root = new TreeNode(maxValue);
        root.left = construct(nums, begin, maxIndex);
        root.right = construct(nums, maxIndex + 1, end);
        return root;
    }
}

合并二叉树

给你两棵二叉树: root1 和 root2 。

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        return merge(root1, root2);
    }

    public TreeNode merge(TreeNode t1, TreeNode t2) {
        if (t1 == null) return t2;
        if (t2 == null) return t1;
        t1.val += t2.val;
        t1.left = merge(t1.left, t2.left);
        t1.right = merge(t1.right, t2.right);
        return t1;
    }
}

下面迭代法中 node1 不为空, node2 为空时不用处理

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if (root1 == null) return root2;
        if (root2 == null) return root1;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root1);
        queue.offer(root2);
        while (!queue.isEmpty()) {
            TreeNode node1 = queue.poll();
            TreeNode node2 = queue.poll();
            // 此时两个节点一定不为空,val相加
            node1.val += node2.val;

            // 如果两棵树左节点都不为空,加入队列
            if (node2.right != null && node1.right != null) {
                queue.offer(node1.right);
                queue.offer(node2.right);
            } 
        
            if (node2.left != null && node1.left != null) {
                queue.offer(node1.left);
                queue.offer(node2.left);
            }

            // 若node1的左右节点为空,直接赋值
            if (node1.right == null && node2.right != null) node1.right = node2.right;
            if (node1.left == null && node2.left != null) node1.left = node2.left;
        }
        return root1;
    }
}

二叉搜索树中的搜索

二叉搜索树是一个有序树
若左子树不空, 则左子树上所有节点的值均小于它的根节点的值;
若右子树不空, 则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉搜索树
二叉搜索树,递归遍历和迭代遍历和普通二叉树都不一样。本题其实就是在二叉搜索树中搜索一个节点。

递归法

// 利用二叉搜索树的特点
class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if(root == null) return null;
        if (root.val == val) return root;
        TreeNode result = null;
        if (root.val > val) result = searchBST(root.left, val);
        if (root.val < val) result = searchBST(root.right, val);
        return result;
    }
}

注意 root.left 和 root.right return 时 怎么 return
哪个是空就返回另一个

// 普通二叉树
class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if (root == null) return null;
        if (root.val == val) return root;
        TreeNode result = null;
        result = searchBST(root.left, val);
        if (result != null) {
            return result;
        }
        return searchBST(root.right, val);
    }
}

迭代
在这里插入图片描述

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;
    }
}

验证二叉搜索树

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。
有了这个特性,验证二叉搜索树,就相当于变成了判断一个序列是不是递增的了。

可以递归中序遍历将二叉搜索树转变成一个数组, // 或集合吧
然后只要比较一下,这个数组是否是有序的,注意二叉搜索树中不能有重复元素。

class Solution {
    List<Integer> list = new ArrayList<>();
    private void traversal(TreeNode root) {
        if (root == null) return;
        traversal(root.left);
        list.add(root.val);
        traversal(root.right);
    }
    public boolean isValidBST(TreeNode root) {
        traversal(root);
        for (int i = 1; i < list.size(); i++) {
            if (list.get(i) <= list.get(i - 1)) return false;
        }
        return true;
    }
}

题目比较容易陷入两个陷阱

1. 不能单纯的比较左节点小于中间节点,右节点大于中间节点就完事了。
我们要比较的是 左子树所有节点小于中间节点,右子树所有节点大于中间节点。

代码随想录算法训练营第二十天 | 最大二叉树、合并二叉树、二叉搜索树中的搜索、验证二叉搜索树_第1张图片

2. 样例中最小节点 可能是int的最小值,如果这样使用最小的int来比较也是不行的。
此时可以初始化比较元素为longlong的最小值。 但是如果更小呢, 可以用双指针法 ,两个节点的值,后一个和前一个比较

class Solution { 
    
    // 为了防止树里的最小值特别特别小,可以用双指针的方法,一个节点和前一个节点进行比较
    TreeNode pre = null;
    public boolean isValidBST(TreeNode root) {
        if (root == null) return true;
        boolean left = isValidBST(root.left);
        // if (!left) return false;
        // 第一个节点前没有节点, pre为 null 所以第一个节点不走下面的if 判断
        if (pre != null && root.val <= pre.val) {  // 前一个节点更到 则false
            return false;
        }
        pre = root;    // 记录前一个节点
        boolean right = isValidBST(root.right);
        return left && right;
    }
}

迭代的中序遍历还不会写

你可能感兴趣的:(算法)