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

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

654.最大二叉树

力扣题目地址(opens new window)

给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:

  • 二叉树的根是数组中的最大元素。
  • 左子树是通过数组中最大值左边部分构造出的最大二叉树。
  • 右子树是通过数组中最大值右边部分构造出的最大二叉树。

通过给定的数组构建最大二叉树,并且输出这个树的根节点。

示例 :

654.最大二叉树

提示:

给定的数组的大小在 [1, 1000] 之间。

思路

递归法 前序遍历
思路和【106.从中序与后序遍历序列构造二叉树】很类似
首先遍历数组找到最大值,保存下标Index
依据下标,分割数组为左数组和有数组
递归法三要素
1.方法入参和返回值 入参:int[] nums 返回值TreeNode node
2.终止条件 数组为空
3.核心逻辑 前序遍历,因为先构造中间节点,然后递归构造左子树和右子树

代码如下

// 时间复杂度O(n) 构建二叉树需要遍历数组所有结点
// 空间复杂度O(n) 构建的二叉树深度最大为n
public TreeNode constructMaximumBinaryTree(int[] nums) {
    if(nums == null){
        return null;
    }
    return travel(nums);
}

public TreeNode travel(int[] nums) {
    if (nums.length == 0)
        return null;

    int rootVal = Integer.MIN_VALUE;
    int index = 0;
    for (int i = 0; i < nums.length; i++) {
        if (nums[i] > rootVal) {
            rootVal = nums[i];
            index = i;
        }
    }

    int[] leftNums = new int[index];
    int[] rightNums = new int[nums.length - index - 1];
    for (int i = 0; i < index; i++) {
        leftNums[i] = nums[i];
    }
    for (int i = index + 1; i < nums.length; i++) {
        rightNums[i - index - 1] = nums[i];
    }

    TreeNode root = new TreeNode(rootVal,null,null);
    root.left = travel(leftNums);
    root.right = travel(rightNums);
    return root;

}

617.合并二叉树

力扣题目链接(opens new window)

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。

你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。

示例 1:

617.合并二叉树

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

思路

先序遍历 递归法
因为需要先访问根节点,然后一层层访问到叶子结点,所以先序遍历符合条件
使用递归法,同时对两个树的左子树和右子树进行递归。这里就用两个树的左子树为例
1.如果A,B两个结点不等于空,那么A,B两树的左子树同时加入递归循环。A,B存在空结点的话,传递null值代替空结点
2.将A,B两树的左子树val之和赋予新结点。
递归法三要素
1.方法入参和返回值 入参:TreeNode root1, TreeNode root2 返回值:TreeNode root
2.中止条件 :两个树都遍历到叶子结点
3.核心逻辑 先序遍历

代码如下

// 时间复杂度O(N)
// 空间复杂度o(n)
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
    return travel(root1, root2);
}

public TreeNode travel(TreeNode root1, TreeNode root2) {
    if (root1 == null && root2 == null) {// 中止条件 :两个树都遍历到叶子结点
        return null;
    }
    int rootVal = 0;

    if (root1 != null)
        rootVal = rootVal + root1.val;
    if (root2 != null)
        rootVal = rootVal + root2.val;
    TreeNode root = new TreeNode(rootVal, null, null);


    if (root1 != null && root2 != null) {
        root.left = mergeTrees(root1.left, root2.left);
        root.right = mergeTrees(root1.right, root2.right);
    } else if (root1 != null && root2 == null) {
        root.left = mergeTrees(root1.left, null);
        root.right = mergeTrees(root1.right, null);
    } else if (root1 == null && root2 != null) {
        root.left = mergeTrees(null, root2.left);
        root.right = mergeTrees(null, root2.right);
    }

    return root;
}

700.二叉搜索树中的搜索

力扣题目地址(opens new window)

给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。

例如,

700.二叉搜索树中的搜索

在上述示例中,如果要找的值是 5,但因为没有节点值为 5,我们应该返回 NULL。

思路

前序遍历 递归

二叉搜索树的特性是 左子树结点小于根节点,右子树结点大于根节点
利用特性,先跟根节点比较,然后在根据比较结果,跟左子树或右子树比较
递归三要素
1.方法入参和返回值 入参:TreeNode root int val 返回值 TreeNode node
2.中止条件 遍历到叶子结点 或者 遇到结点值等于val
3.核心逻辑 前序遍历 要先访问根节点,然后访问左右子树,前序遍历满足条件

代码如下

// 时间复杂度o(n)
// 空间复杂度o(n)
public TreeNode searchBST(TreeNode root, int val) {
    if (root == null)
        return null;
    return travel(root, val);
}

public TreeNode travel(TreeNode root, int val) {

    if (root.val == val) {// 中止条件 遍历到叶子结点  或者 遇到结点值等于val
        return root;
    }
    if (root.right == null && root.left == null) {
        return null;
    }

    TreeNode node = null;
    if (root.val > val && root.left != null) {// 核心逻辑 前序遍历 要先访问根节点,然后访问左右子树,前序遍历满足条件
        node = travel(root.left, val);

    }else if (root.val < val && root.right != null) {
        node = travel(root.right, val);
    }
    return node;

}

98.验证二叉搜索树

力扣题目链接(opens new window)

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

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

98.验证二叉搜索树

思路:递归法

将二叉搜索树中序遍历,输出的结果是升序排序的
那么先进行中序遍历,判断中序遍历结果是否为升序即可

代码如下

    // 时间复杂度o(n)
    // 空间复杂度o(n)
public boolean isValidBST(TreeNode root) {
    if (root == null)
        return true;
    List<Integer> result = new ArrayList<>();
    travel(root, result);

    for (int i = 0; i < result.size() - 1; i++) {
        if (result.get(i) >= result.get(i + 1))
            return false;
    }
    return true;
}

// 中序遍历
public void travel(TreeNode root, List<Integer> result) {

    if (root == null) {
        return;
    }

    travel(root.left, result);
    result.add(root.val);
    travel(root.right, result);
}

思路:递归法(更优解)

在递归的过程中判断中序遍历的顺序,效率比中序遍历结束后判断数组顺序要高
观察中序遍历的代码:
1.中序遍历的结果由【result.add(root.val)】 加入
2.那么保存root.val,在下次调用result.add(root.val)时,比较顺序。
3.即可在二叉树遍历过程中,比较结点大小

 public void travel(TreeNode root, List<Integer> result) {
 	if (root == null) {
       return;
    }

   travel(root.left, result);// 左子树
   result.add(root.val);
   travel(root.right, result);// 右子树
 }

代码如下

// 时间复杂度o(n)
// 空间复杂度o(n)
TreeNode pre = null;
public boolean isValidBST(TreeNode root) {
    if (root == null)
        return true;
    return travel(root);
}

// 中序遍历
public boolean travel(TreeNode root) {
    if (root == null) {
        return true;
    }

    if (!travel(root.left))
        return false;
    if (pre != null && pre.val >= root.val) {
        return false;
    }
    pre = root;

    if (!travel(root.right))
        return false;
    return true;
}

思路:迭代法

在中序遍历迭代法的基础上做改动
新增preNode记录中序遍历的前一个结点
前一个结点和当前结点作比较即可

代码如下

// 时间复杂度o(n)
// 空间复杂度o(n)

TreeNode preNode = null;
public Boolean inorderTraversal1(TreeNode root) {
    Stack<TreeNode> stack = new Stack<>();
    TreeNode cur = root;
    while (!stack.isEmpty() || cur != null) {// 当指针元素为空 并且 栈为空时,结束循环
        if (cur != null) {
            stack.push(cur);
            cur = cur.left;

        } else {
            cur = stack.pop();

            if (preNode != null && preNode.val >= cur.val)
                return false;
            preNode = cur;
            cur = cur.right;

        }
    }
    return true;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值