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

654.最大二叉树

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

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

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

示例 :

654.最大二叉树

提示:

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

思路:

递归三部曲:

  1. 参数和返回值:数组可以在全局定义,不需要作为参数。参数是记录需要进行寻找最大值的数组区间的首尾两端下标即可。返回值应该是作为根节点的节点值。
  2. 终止条件:当首尾下标,left>right肯定是不正确的区间,说明区间不存在,直接返回None。如果left==right,说明区间只有一个数,直接将其作为节点返回。
  3. 递归逻辑:若是一个正常的区间,首先在这个区间中找到最大值下标,记录下来等着最后返回。由于当前处于区间[left,right],所以该节点middle会将区间分为两个部分,即left到middle,middle到right,在这两个区间分别调用递归作为该节点的两个孩子值,然后返回该节点。

代码实现如下:

# Definition for a binary tree node.

# class TreeNode:

#     def __init__(self, val=0, left=None, right=None):

#         self.val = val

#         self.left = left

#         self.right = right

class Solution:

    def constructMaximumBinaryTree(self, nums: List[int]) -> Optional[TreeNode]:

        self.arr = nums

        return self.getmaxtree(0, len(nums)-1)

   

    def getmaxtree(self, left:int, right:int) -> Optional[TreeNode]:    # 左闭右闭

        if left > right:

            return None

        if left == right:

            node = TreeNode(self.arr[left])

            return node

        maxval = self.arr[left]

        middle = left

        for i in range(left+1, right+1):

            if self.arr[i] > maxval:

                maxval = self.arr[i]            # 这里记得要更新maxval值,debug才发现

                middle = i

        root = TreeNode(self.arr[middle])

        root.left = self.getmaxtree(left, middle-1)             # 注意是left,不是0

        root.right = self.getmaxtree(middle+1, right)           # 注意是right, 不是len(self.arr)-1

        return root

       

规范代码如下:

# Definition for a binary tree node.# class TreeNode:#     def __init__(self, val=0, left=None, right=None):#         self.val = val#         self.left = left#         self.right = rightclass Solution:

    def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:

        if len(nums) == 1:

            return TreeNode(nums[0])

        node = TreeNode(0)

        # 找到数组中最大的值和对应的下标

        maxValue = 0

        maxValueIndex = 0

        for i in range(len(nums)):

            if nums[i] > maxValue:

                maxValue = nums[i]

                maxValueIndex = i

        node.val = maxValue

        # 最大值所在的下标左区间 构造左子树

        if maxValueIndex > 0:

            new_list = nums[:maxValueIndex]

            node.left = self.constructMaximumBinaryTree(new_list)

        # 最大值所在的下标右区间 构造右子树

        if maxValueIndex < len(nums) - 1:

            new_list = nums[maxValueIndex+1:]

            node.right = self.constructMaximumBinaryTree(new_list)

        return node

使用下标

class Solution:

    def traversal(self, nums: List[int], left: int, right: int) -> TreeNode:

        if left >= right:

            return None

        maxValueIndex = left

        for i in range(left + 1, right):

            if nums[i] > nums[maxValueIndex]:

                maxValueIndex = i

        root = TreeNode(nums[maxValueIndex])

        root.left = self.traversal(nums, left, maxValueIndex)

        root.right = self.traversal(nums, maxValueIndex + 1, right)

        return root

    def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:

        return self.traversal(nums, 0, len(nums))

使用切片:

class Solution:

    def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:

        if not nums:

            return None

        max_val = max(nums)

        max_index = nums.index(max_val)

        node = TreeNode(max_val)

        node.left = self.constructMaximumBinaryTree(nums[:max_index])

        node.right = self.constructMaximumBinaryTree(nums[max_index+1:])

        return node

617.合并二叉树

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

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

示例 1:

617.合并二叉树

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

思路:

递归三部曲:

  1. 参数和返回值:两棵树的节点作为传入参数。返回一颗合并树,节点作为返回值。
  2. 终止条件:两个传入节点都为空。
  3. 递归逻辑:比较两个传入节点,如果一个为空,该节点值为另一个的值;否则为两个节点值之和,同时合并后的节点的孩子,是继续对两棵树对应位置的节点的递归调用得到的节点。需要考虑传入节点是否存在一个空值的情况,为了取得对应位置的节点,即本过程对应位置的左右孩子,若判断到其中一个节点为空值,为其赋值一个默认节点(属性为默认空值)。!!后来发现这部分考虑其实多余了,直接返回另外一个节点即可,因为返回另外一个节点,则其孩子也会被保留,而为空的节点本来就不存在孩子,对应位置的节点必然是非空节点的孩子。 但以下我自己的实现由于不是直接返回非空节点,所以还是需要有这一部分的操作考虑。

代码实现如下:

# Definition for a binary tree node.

# class TreeNode:

#     def __init__(self, val=0, left=None, right=None):

#         self.val = val

#         self.left = left

#         self.right = right

class Solution:

    def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:

        return self.getnewnode(root1, root2)

       

    def getnewnode(self, node1: Optional[TreeNode], node2: Optional[TreeNode]) -> Optional[TreeNode]:

        if not node1 and not node2:

            return None

        node = TreeNode()

        if node1:

            node.val += node1.val

        else:

            node1 = TreeNode()

        if node2:

            node.val += node2.val

        else:

            node2 = TreeNode()

        node.left = self.getnewnode(node1.left, node2.left)

        node.right = self.getnewnode(node1.right, node2.right)

        return node

规范代码:

# Definition for a binary tree node.# class TreeNode:#     def __init__(self, val=0, left=None, right=None):#         self.val = val#         self.left = left#         self.right = right

class Solution:

    def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:

        # 递归终止条件:

        #  但凡有一个节点为空, 就立刻返回另外一个. 如果另外一个也为None就直接返回None.

        if not root1:

            return root2

        if not root2:

            return root1

        # 上面的递归终止条件保证了代码执行到这里root1, root2都非空.

        root1.val += root2.val # 中

        root1.left = self.mergeTrees(root1.left, root2.left) #左

        root1.right = self.mergeTrees(root1.right, root2.right) # 右

        

        return root1 # ⚠️ 注意: 本题我们重复使用了题目给出的节点而不是创建新节点. 节省时间, 空间.

迭代:

class Solution:

    def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:

        if not root1:

            return root2

        if not root2:

            return root1

        queue = deque()

        queue.append(root1)

        queue.append(root2)

        while queue:

            node1 = queue.popleft()

            node2 = queue.popleft()

            # 更新queue

            # 只有两个节点都有左节点时, 再往queue里面放.

            if node1.left and node2.left:

                queue.append(node1.left)

                queue.append(node2.left)

            # 只有两个节点都有右节点时, 再往queue里面放.

            if node1.right and node2.right:

                queue.append(node1.right)

                queue.append(node2.right)

            # 更新当前节点. 同时改变当前节点的左右孩子.

            node1.val += node2.val

            if not node1.left and node2.left:

                node1.left = node2.left

            if not node1.right and node2.right:

                node1.right = node2.right

        return root1


700.二叉搜索树中的搜索

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

例如,

700.二叉搜索树中的搜索

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

思路:

递归三部曲:

  1. 参数和返回值:参数为传入节点和搜索值。返回值为所找节点。
  2. 终止条件:找到了搜索值,返回该节点。遇到叶子节点且未找到搜索值,返回None。
  3. 递归逻辑:对当前节点的孩子继续调用递归,先对左孩子调用,如果存在返回值,则返回该值,否则继续对右孩子调用,如果存在则返回,不存在返回None。(忘记该题是二叉搜索树,应该判断节点大小和搜索值大小,如果搜索值小则搜索左孩子,否则搜索右孩子。自己实现的做法是任意二叉树)

代码实现如下:

# Definition for a binary tree node.

# class TreeNode:

#     def __init__(self, val=0, left=None, right=None):

#         self.val = val

#         self.left = left

#         self.right = right

class Solution:

    def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:

        return self.findnode(root, val)

    def findnode(self, node: Optional[TreeNode], val: int) -> Optional[TreeNode]:

        if not node:

            return None

        if node.val == val:

            return node

        if (des := self.findnode(node.left, val)) or (des := self.findnode(node.right, val)):

            return des

        else:

            return None

规范代码:

class Solution:

    def searchBST(self, root: TreeNode, val: int) -> TreeNode:

        # 为什么要有返回值:

        #   因为搜索到目标节点就要立即return,

        #   这样才是找到节点就返回(搜索某一条边),如果不加return,就是遍历整棵树了。

        if not root or root.val == val:

            return root

        if root.val > val:

            return self.searchBST(root.left, val)

        if root.val < val:

            return self.searchBST(root.right, val)

迭代:

class Solution:

    def searchBST(self, root: TreeNode, val: int) -> TreeNode:

        while root:

            if val < root.val: root = root.left

            elif val > root.val: root = root.right

            else: return root

        return None

栈-遍历

class Solution:

    def searchBST(self, root: TreeNode, val: int) -> TreeNode:

        stack = [root]

        while stack:

            node = stack.pop()

            # 根据TreeNode的定义

            # node携带有三类信息 node.left/node.right/node.val

            # 找到val直接返回node 即是找到了该节点为根的子树

            # 此处node.left/node.right/val的前后顺序可打乱

            if node.val == val:

                return node

            if node.right:

                stack.append(node.right)

            if node.left:

                stack.append(node.left)

        return None


98.验证二叉搜索树

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

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

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

98.验证二叉搜索树

思路:

一开始没自己实现,思路不多,但能想到可能会有的坑:在判断的时候不能只判断左右孩子是否小(大)于节点值,还需要注意无论是左右孩子,都要满足该节点和该节点父亲的关系保持一致。(例如:左孩子的右孩子不能大于本节点)

根据文字解析提供的思路:一颗二叉搜索树的中序遍历应该是一个有序数组,所以对该二叉树进行中序遍历得到一个数组,如果是有序的则验证成功,否则验证失败。

递归三部曲:

  1. 参数和返回值: 参数是传入节点。返回值是None
  2. 终止条件:节点为空。
  3. 递归逻辑:先对左孩子进行递归,然后对本节点进行操作(加入数组),然后对右孩子进行递归。

代码实现如下:

# Definition for a binary tree node.

# class TreeNode:

#     def __init__(self, val=0, left=None, right=None):

#         self.val = val

#         self.left = left

#         self.right = right

class Solution:

    def isValidBST(self, root: Optional[TreeNode]) -> bool:

        if not root:

            return True

        self.arr = []

        self.visit(root)

        maxvalue = self.arr[0]

        for i in range(1, len(self.arr)):

            if self.arr[i] <= maxvalue:

                return False

            maxvalue = self.arr[i]

        return True

    def visit(self, node: Optional[TreeNode]) -> None:

        if not node:

            return

        self.visit(node.left)

        self.arr.append(node.val)

        self.visit(node.right)

递归法(版本二)设定极小值,进行比较

class Solution:

    def __init__(self):

        self.maxVal = float('-inf')  # 因为后台测试数据中有int最小值

    def isValidBST(self, root):

        if root is None:

            return True

        left = self.isValidBST(root.left)

        # 中序遍历,验证遍历的元素是不是从小到大

        if self.maxVal < root.val:

            self.maxVal = root.val

        else:

            return False

        right = self.isValidBST(root.right)

        return left and right

递归法(版本三)直接取该树的最小值

# Definition for a binary tree node.# class TreeNode:#     def __init__(self, val=0, left=None, right=None):#         self.val = val#         self.left = left#         self.right = rightclass Solution:

    def __init__(self):

        self.pre = None  # 用来记录前一个节点

    def isValidBST(self, root):

        if root is None:

            return True

        left = self.isValidBST(root.left)

        if self.pre is not None and self.pre.val >= root.val:

            return False

        self.pre = root  # 记录前一个节点

        right = self.isValidBST(root.right)

        return left and right

迭代法

# Definition for a binary tree node.# class TreeNode:#     def __init__(self, val=0, left=None, right=None):#         self.val = val#         self.left = left#         self.right = rightclass Solution:

    def isValidBST(self, root):

        stack = []

        cur = root

        pre = None  # 记录前一个节点

        while cur is not None or len(stack) > 0:

            if cur is not None:

                stack.append(cur)

                cur = cur.left  # 左

            else:

                cur = stack.pop()  # 中

                if pre is not None and cur.val <= pre.val:

                    return False

                pre = cur  # 保存前一个访问的结点

                cur = cur.right  # 右

        return True

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1549548.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

番外篇 | 复现AC-YOLOv5,进行自动化织物缺陷检测

前言:Hello大家好,我是小哥谈。我们提出了一种基于AC-YOLOv5的新型纺织缺陷检测方法。将空洞空间金字塔池化(ASPP)模块引入YOLOv5主干网络中,提出了squeeze-and-excitation(CSE)通道注意力模块,并将其引入到YOLOv5主干网络中。🌈 目录 🚀1.基础概念 🚀2.添…

Chrome浏览器如何修改语言(修改成英文、中文)

一、背景 有的时候需要修改chrome浏览器的语言&#xff0c;比如如下是中文&#xff0c;我要修改成英文 二、下面的方法已经无效了 在语言里添加"英语"并且置顶&#xff0c;试了很久&#xff0c;设置完后重启浏览器什么的&#xff0c;都无法改成英文。 这个可能…

ECMAScript 与 JavaScript 的区别详解

ECMAScript 与 JavaScript 的区别详解 在前端开发的学习过程中&#xff0c;很多开发者会遇到两个常见的术语&#xff1a;ECMAScript 和 JavaScript。这两个术语常常被混淆&#xff0c;因为它们密切相关&#xff0c;甚至有时被认为是同一件事。本文将详细解析 ECMAScript 和 Ja…

青动CRM V3.2.1

全面解决企业销售团队的全流程客户服务难题旨在助力企业销售全流程精细化、数字化管理&#xff0c;全面解决企业销售团队的全流程客户服务难题&#xff0c;帮助企业有效盘活客户资源、量化销售行为&#xff0c;合理配置资源、建立科学销售体系&#xff0c;提升销售业绩。标准授…

【面试题】软件测试实习(含答案)

软件测试实习常见面试题&#xff0c;主要是功能测试相关的基础问题 目录 一、软件测试基础 1、介绍一下你最近的项目&#xff0c;以及工作职责 2、软件项目的测试流程? 3、黑盒测试与白盒测试的区别? 4、黑盒测试常见的设计方法?怎么理解等价类方法和边界值方法 1&…

言语理解(2)

B B出现在文章中的第一句话&#xff0c;属于转折前的内容非重点 在这一过程中&#xff0c;属于对前面的指代&#xff0c;后面可以引出文章中的中心内容 A D没有提及到农村&#xff0c;C选项和文段中的最后一句话是相契合的 B 色彩是文章中的主题词&#xff0c;不过属于转折&…

SpringBoot搭建

第一种创建方式 第二种创建方式 第三种创建 第四种手动创建 最后把controller写好

解决Windows远程桌面 “为安全考虑,已锁定该用户账户,原因是登录尝试或密码更改尝试过多,请稍后片刻再重试,或与系统管理员或技术支持联系“问题

根本原因就是当前主机被通过远程桌面输入了过多的错误密码&#xff0c;被系统锁定。这种情况多数是你的服务器远程桌面被人试图攻击了&#xff0c;不建议取消系统锁定策略。如果阿里云或者腾讯云主机&#xff0c;只需要在管理后台通过管理终端或者VNC登陆一次&#xff0c;锁定即…

RTA-OS Port Guide学习(三)-基于S32K324 OS

文章目录 前言HardwareSupported DevicesRegister UsageInitializationModificationRequired OS resourcesInterruptsInterrupt Priority LevelsAllocation of ISRs to Interrupt VectorsVector TableWriting Category 1 Interrupt HandlersWriting Category 2 Interrupt Handl…

【Echarts】折线图和柱状图如何从后端动态获取数据?

&#x1f680;个人主页&#xff1a;一颗小谷粒 &#x1f680;所属专栏&#xff1a;Web前端开发 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1.1 前端数据分析 1.2 数据库表分析 1.3 后端数据处理 1.4 前端接收数据 继上一篇文章&…

Linux入门2——初识Linux权限

目录 0. Linux下的用户 1.文件访问者的分类 2.文件类型和访问权限 3. 文件权限值的表示方法 4.文件访问权限的相关设置方法 4.1 修改文件的访问权限 4.2修改文件的拥有者和所属组 0. Linux下的用户 在学习Linux权限之前&#xff0c;我们要先来了解Linux下的用户&#x…

【文心智能体 | AI大师工坊】如何使用智能体插件,完成一款旅游类智能体的开发,来体验一下我的智能体『​​​​​​​厦门CityWalk』

目录 1.1、智能体运行效果 1.2、创作灵感来源 1.3、如何制作智能体 1.4、可能会遇到的几个问题 1.5、快速调优指南 『厦门CityWalk&#x1f680;』我的优质智能体&#xff1a;https://0nxj3k.smartapps.baidu.com/?_swebfr1&_swebScene3621000000000000 在当今这个全…

智慧水利综合解决方案

1. 智慧水利综合解决方案概述 智慧水利综合解决方案旨在通过集成先进技术&#xff0c;实现水利管理的智能化和高效化。该方案涵盖平台建设、业务系统建设和系统集成服务三大应用场景&#xff0c;通过数字孪生、GIS平台开发等技术手段&#xff0c;全面提升水利行业的管理能力和…

Elasticsearch学习笔记(2)

索引库操作 在Elasticsearch中&#xff0c;Mapping是定义文档字段及其属性的重要机制。 Mapping映射属性 type&#xff1a;字段数据类型 1、字符串&#xff1a; text&#xff1a;可分词的文本&#xff0c;适用于需要全文检索的情况。keyword&#xff1a;用于存储精确值&am…

找不到msvcp110.dll怎么办,总结6种解决msvcp110.dll的方法

在电脑使用过程中&#xff0c;我们可能会遇到各种各样的问题&#xff0c;其中之一就是系统提示某个文件丢失。msvcp110.dll丢失是一个比较常见的问题&#xff0c;它可能导致某些程序无法正常运行。那么&#xff0c;如何解决这个问题呢&#xff1f;本文将详细介绍6种修复msvcp11…

Yolov10环境配置

参考文章&#xff1a;1.YOLOv10超详细环境搭建以及模型训练&#xff08;GPU版本&#xff09;-CSDN博客 2.Windows下安装pytorch教程(下载.whl的方式)_pytorch whl-CSDN博客 安装步骤和文件夹顺序一样 1.安装CUDA和cuDNN 1.1安装CUDA 1.1.1查看当前你的电脑显卡支持的最高CUD…

【微服务】springboot 实现动态修改接口返回值

目录 一、前言 二、动态修改接口返回结果实现方案总结 2.1 使用反射动态修改返回结果参数 2.1.1 认识反射 2.1.2 反射的作用 2.1.3 反射相关的类 2.1.4 反射实现接口参数动态修改实现思路 2.2 使用ControllerAdvice 注解动态修改返回结果参数​​​​​​​ 2.2.1 注解…

构造性神经组合优化的学习编码需要反悔

文章目录 Abstract1 Introduction2 Related Work用于构造性启发式的深度强化学习当前用于更好编码的方法3 LCH-Regret学习构造性启发式反悔机制LCH - Regret 机制的 L R L_R LR​Abstract 深度强化学习的神经组合优化中,学习构造性启发式(LCH)通过快速的自回归解构建过程实…

【ChromeDriver安装】爬虫必备

以下是安装和配置 chromedriver 的步骤&#xff1a; 1. 确认 Chrome 浏览器版本 打开 Chrome 浏览器&#xff0c;点击右上角的菜单按钮&#xff08;三个点&#xff09;&#xff0c;选择“帮助” > “关于 Google Chrome”。 2. 下载 Chromedriver 根据你的 Chrome 版本&…

原宝,四周年快乐!

原神&#xff0c;公测于2020年9月28日开启。 现在已经是第4个年头了&#xff0c;7个国家已经开放了6个&#xff0c;来到了火之国。其实自从2022年继续开放游戏版号以来&#xff0c;好品质的二次元游戏、三端游戏也是层出不穷。无论是立绘&#xff0c;建模都有非常优秀的作品。…