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

news/2024/7/24 10:06:09 标签: 算法, 数据结构, leetcode

二叉树 part06

  • 654.最大二叉树
    • 解题思路
  • 617.合并二叉树
    • 解题思路
  • 700.二叉搜索树中的搜索
    • 解题思路
  • 98.验证二叉搜索树
    • 解题思路
    • 误区

654.最大二叉树

又是构造二叉树,昨天大家刚刚做完 中序后序确定二叉树,今天做这个 应该会容易一些, 先看视频,好好体会一下 为什么构造二叉树都是 前序遍历
题目链接/文章讲解:654.最大二叉树
视频讲解:654.最大二叉树

解题思路

和昨天最后2道题思路类似,比那2道题处理起来还更简单一些
解题步骤:

  1. 递归终止条件判断:只有1个元素/没有元素
  2. 找最大值将其加入树,根据最大值所在下标划分左右子树

注意点:

  1. 用下标来确定左右子树的遍历范围,不用开辟新空间
  2. 所有区间范围统一一个原则,这里是左闭右开
class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return constructMaximumBinaryTree1(nums, 0, nums.length);
    }
    public TreeNode constructMaximumBinaryTree1(int[] nums, int leftIndex, int rightIndex){
        if(rightIndex - leftIndex < 1) return null; // 没有元素了
        if(rightIndex - leftIndex == 1) return new TreeNode(nums[leftIndex]); //只有1个元素表明到了叶子节点
        // 找最大值及最大值所在位置
        int maxIndex = leftIndex;  // 最大值所在位置
        int maxVal = nums[maxIndex]; // 最大者所在下标
        for(int i = leftIndex + 1; i < rightIndex; i++){
            if(nums[i] > maxVal){
                maxVal = nums[i];
                maxIndex = i;
            }
        }
        TreeNode root = new TreeNode(maxVal);
        // 根据maxIndex划分左右子树
        root.left = constructMaximumBinaryTree1(nums, leftIndex, maxIndex);
        root.right = constructMaximumBinaryTree1(nums, maxIndex + 1, rightIndex);

        return root;
    }
}

617.合并二叉树

这次是一起操作两个二叉树了, 估计大家也没一起操作过两个二叉树,也不知道该如何一起操作,可以看视频先理解一下。 优先掌握递归。
题目链接/文章讲解:617.合并二叉树
视频讲解:617.合并二叉树 ## 解题思路

解题思路

考查同时对两个二叉树同时操作
理论上前中后序遍历都可以,层序迭代也可以。但是leecode要求必须从根节点开始合并,所以只能用前序或者层序。
思路:

  1. 终止条件:两棵树遍历的当前节点至少有一个为null
  2. 单层递归逻辑:把两棵树的值加到一起
// 递归  前序
class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if(root1 == null) return root2;
        if(root2 == null) return root1;
        TreeNode root = new TreeNode(0);
        // 中
        root.val = root1.val + root2.val;
        // 左
        root.left = mergeTrees(root1.left, root2.left);
        // 右
        root.right = mergeTrees(root1.right, root2.right);

        return root;
    }
}
// 使用队列迭代
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 = node1.val + node2.val;
            // 如果两棵树左节点都不为空,加入队列
            if (node1.left != null && node2.left != null) {
                queue.offer(node1.left);
                queue.offer(node2.left);
            }
            // 如果两棵树右节点都不为空,加入队列
            if (node1.right != null && node2.right != null) {
                queue.offer(node1.right);
                queue.offer(node2.right);
            }
            // 若node1的左节点为空,直接赋值
            if (node1.left == null && node2.left != null) {
                node1.left = node2.left;
            }
            // 若node1的右节点为空,直接赋值
            if (node1.right == null && node2.right != null) {
                node1.right = node2.right;
            }
        }
        return root1;
    }
}

700.二叉搜索树中的搜索

递归和迭代 都可以掌握以下,因为本题比较简单, 了解一下 二叉搜索树的特性
题目链接/文章讲解: 700.二叉搜索树中的搜索
视频讲解:700.二叉搜索树中的搜索

解题思路

二叉搜索树是一个有序树,它的递归遍历和迭代遍历和普通二叉树都不一样。

  1. 终止条件:root为空或者找到这个数值
  2. 单层递归逻辑:因为二叉搜索树的节点是有序的,所以可以有方向的去搜索。
    如果root.val > val,搜索左子树,如果root.val < val,就搜索右子树,最后如果都没有搜索到,就返回NULL。
// 递归
class Solution {
    public TreeNode searchBST(TreeNode root, int val) {
        if(root == null || 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;
    }
}
// 层序迭代
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;
    }
}

98.验证二叉搜索树

但本题是有陷阱的,可以自己先做一做,然后在看题解,看看自己是不是掉陷阱里了。这样理解的更深刻。
题目链接/文章讲解:https://programmercarl.com/0098.%E9%AA%8C%E8%AF%81%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html
视频讲解:https://www.bilibili.com/video/BV18P411n7Q4

解题思路

  1. 遇到 搜索树,一定想着中序遍历,这样才能利用上特性.如果中序遍历下元素是单调递增的,那它就是一颗二叉搜索树。
  2. 遍历二叉搜索树时,如何用两个指针比较元素大小。

误区

  1. 不能单纯的比较左节点小于中间节点,右节点大于中间节点就完事了。我们要比较的是 左子树所有节点小于中间节点,右子树所有节点大于中间节点。
if (root->val > root->left->val && root->val < root->right->val) {
    return true;
} else {
    return false;
}
  1. 样例中最小节点 可能是int的最小值,如果这样使用最小的int来比较也是不行的。此时可以初始化比较元素为longlong的最小值。但是这样解决不是最优的,可以用指针来进行比较
// 递归 中序遍历  定义TreeNode prev = null;
class Solution {
    TreeNode prev = null;
    public boolean isValidBST(TreeNode root) {
        if(root == null) return true;
        if(!isValidBST(root.left)) return false;  // 左
        // 中
        if(prev != null && root.val <= prev.val) return false;
        prev = root;
        return isValidBST(root.right);  // 右
       
    }
}
// 递归 中序遍历  定义long prev
class Solution {
    private long prev = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        if(root == null) return true;
        if(!isValidBST(root.left)) return false;  // 左
        // 中
        if(root.val <= prev) return false;
        prev = root.val;
        return isValidBST(root.right);  // 右    
    }
}

http://www.niftyadmin.cn/n/5328346.html

相关文章

x-cmd pkg | tsx - Node.js 的直接替代品

目录 简介首次用户功能特点竞品和相关作品进一步探索 简介 tsx 代表 “TypeScript execute”&#xff0c;由 TypeScript 编写&#xff0c;内部使用由 Go 语言编写的 esbuild 核心二进制实现超快的 TypeScript 编译&#xff0c;旨在增强 Node.js 以无缝运行 TypeScript / ESM /…

ChatGPT 淘金潮(全)

原文&#xff1a;The ChatGPT GoldRush 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 一、ChatGPT 简介 什么是 ChatGPT&#xff1f; ChatGPT 是由 OpenAI 基于 GPT-4 架构创建的大型语言模型。它旨在理解和回应自然语言文本输入&#xff0c;使得可以与机器进行对话…

【数据库原理】(27)数据库恢复

在数据库系统中&#xff0c;恢复是指在发生某种故障导致数据库数据不再正确时&#xff0c;将数据库恢复到已知正确的某一状态的过程。数据库故障可能由多种原因引起&#xff0c;包括硬件故障、软件错误、操作员失误以及恶意破坏。为了确保数据库的安全性和完整性&#xff0c;数…

第二十五章 $ZF Callout 快速参考 - $ZF(-5) Call by System ID

文章目录 第二十五章 $ZF Callout 快速参考 - $ZF(-5) Call by System ID$ZF(-5): Call by System ID$ZF(-5)$ZF(-4, 1)$ZF(-4, 2)$ZF(-4, 3) 第二十五章 $ZF Callout 快速参考 - $ZF(-5) Call by System ID $ZF(-5): Call by System ID $ZF(-5) 函数允许应用程序加载 Callou…

600 条 Linux 运维命令总结

1. 基本命令 uname -m 显示机器的处理器架构 uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 (SMBIOS / DMI) hdparm -i /dev/hda 罗列一个磁盘的架构特性 hdparm -tT /dev/sda 在磁盘上执行测试性读取操作系统信息 arch 显示机器的处理器架构 uname -m 显示…

【RT-DETR改进涨点】MPDIoU、InnerMPDIoU损失函数中的No.1(包含二次创新)

前言 大家好&#xff0c;我是Snu77&#xff0c;这里是RT-DETR有效涨点专栏。 本专栏的内容为根据ultralytics版本的RT-DETR进行改进&#xff0c;内容持续更新&#xff0c;每周更新文章数量3-10篇。 专栏以ResNet18、ResNet50为基础修改版本&#xff0c;同时修改内容也支持Re…

Linux下文件的创建写入读取编程

在linux下操作一个文件&#xff0c;首先要保证文件的存在&#xff08;不存在就创建&#xff09;&#xff0c;接着打开文件&#xff08;打开成功&#xff09;并得到文件描述符&#xff0c;接着在进行读写操作&#xff0c;最后还需要关闭文件。如果我们对文件进行读写之后不关闭文…

【征服redis3】一文征服redis的jedis客户端

使用数据库的时候&#xff0c;我们可以用JDBC来实现mysql数据库与java程序之间的通信&#xff0c;为了提高通信效率&#xff0c;我们有了数据库连接池比如druid等等。而我们想通过Java程序控制redis&#xff0c;同样可以借助一些工具来实现&#xff0c;这就是redis客户端&#…