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

今日内容

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

Leetcode. 654 最大二叉树

文章链接:代码随想录 (programmercarl.com)

题目链接:654. 最大二叉树 - 力扣(LeetCode)

本题与前一天做的105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode) 和106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode) 思想类似。都是要找到一个“分水岭”后,再分别对其左右进行处理。

那么就直接按照这两题的解决思路进行处理。在构造二叉树的问题中,我们常用前序遍历解决,因为要先确定根节点后,再分别构造左右子树,这也是很符合我们的思维逻辑的。

本题代码如下:

/**
 * 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) {
        if (nums.length == 0){return null;}
        TreeNode root = findMax(nums, 0, nums.length);
        return root;
    }

    public TreeNode findMax(int[] nums, int start, int end){
        if (start == end){return null;} // 没有元素了
        
        int max = -1;
        int delimeterIndex = 0;
        // 寻找当前数组最大值
        for (int i = start; i < end; i++){
            if (nums[i] > max){
                max = nums[i];
                delimeterIndex = i;
            }
        }
        TreeNode root = new TreeNode(max);

        // 左右分割
        int leftStart = start;
        int leftEnd = delimeterIndex;
        int rightStart = delimeterIndex + 1;
        int rightEnd = end;

        root.left = findMax(nums, leftStart, leftEnd);
        root.right = findMax(nums, rightStart, rightEnd);
        return root;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(n) 

Leetcode. 617 合并二叉树 

文章链接:代码随想录 (programmercarl.com)

题目链接:617. 合并二叉树 - 力扣(LeetCode)

本题思路就是同时遍历两棵二叉树,并将它们的结果覆盖到其中某一棵上。(当然,也可以新建一个二叉树记录结果)。

这样我们可以写出代码:

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;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

Leetcode. 700 二叉搜索树中的搜索

文章链接:代码随想录 (programmercarl.com)

题目链接:700. 二叉搜索树中的搜索 - 力扣(LeetCode)

二叉搜索树的特点:

  1. 若左子树不空,则左子树上所有节点的值都比根节点的值小
  2. 若右子树不空,则右子树上所有节点的值都比根节点的值大
  3. 左右子树都是二叉搜索树 

所以利用起搜索树的特点,本题要使用中序遍历。

思路就是看当前节点的值是否就是要找的值,不是的话比较大小。比目标值大就往左子树找,比目标值小就往右子树找。

代码如下:

// 递归法
class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if (root == null || root.val == val){return root;}
        TreeNode n = new TreeNode();
        if (root.val < val){
            n = searchBST(root.right, val);
        } else if (root.val > val){
            n = searchBST(root.left, val);
        } else {
            return n;
        }
        return n;
    }
}
// 迭代法
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 root;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

Leetcode. 98 验证二叉搜索树

文章链接:代码随想录 (programmercarl.com)

题目链接:98. 验证二叉搜索树 - 力扣(LeetCode)

一开始我的思路就是只比较根节点的值和其左右节点的值就好。但是这样就掉入“陷阱”了。因为二叉搜索树的定义是  左/右子树上所有节点的值都比根节点的值小/大。按照我一开始的思路只能保证某一个节点符合这个定义,但不能保证整个子树符合这个定义。

对于二叉搜索树,我们依然使用中序遍历。

解题思路就是:记录当前子树的根节点值,按照二叉搜索树特性,在中序遍历下,节点值应该不断递增。因此若出现某一节点值小于前一个节点,那么就不是二叉搜索树。

代码如下:

class Solution {

    TreeNode pre = null; // 用于记录前一个节点的值
    public boolean isValidBST(TreeNode root) {
        if (root == null){return true;} // 二叉搜索树可以为空
        
        boolean left = isValidBST(root.left);
        if (pre != null && pre.val >= root.val){return false;} // 将当前节点值与前一个节点值进行比较  
        pre = root;
        boolean right = isValidBST(root.right);
        
        return left && right;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

根据二叉搜索树用中序遍历得到的节点值递增这一特性,我们还可以用中序遍历把二叉搜索树所有节点遍历出来,放到一个数组中。之后遍历数组,看看是否为递增数组。

代码如下:

// 查看数组是否递增
class Solution {
    public boolean isValidBST(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        findValid(root, list);
        for (int i = 1; i < list.size(); i++){
            if (list.get(i) <= list.get(i - 1)){
                return false;
            }
        }
        return true;
    }

    public void findValid(TreeNode node, List<Integer> list){
        if (node == null){return;}
        findValid(node.left, list);
        list.add(node.val);
        findValid(node.right, list);
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

总结

总是理解了思路,但是代码写出来就一堆小问题。不过确实感觉越做越顺了,起码不会像之前一样碰到题目毫无头绪。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DonciSacer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值