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

news2024/11/18 21:46:19

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.coloradmin.cn/o/2175289.html

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

相关文章

LCD显示屏接口

LCD显示屏接口 设备对外接口&#xff1a;VGA、DVI、HDMIHDMI接口接口定义发展历史HDMI特点HDMI接口类型 设备对内接口&#xff1a;串口、并口小屏&#xff08;I2C、SPI、UART&#xff09;中屏&#xff1a;MCU、RGBRGB接口 MCU LCD屏和RGB LCD屏的区别大屏&#xff1a;MIPI、LVD…

OCR Fusion: EasyOCR/Tesseract/PaddleOCR/TrOCR/GOT

文章目录 前言一、基类 OCRExecutorBase二、EasyOCR1.安装2.模型下载3.DEMO 三、Tesseract1.安装2.使用问题3.DEMO 四、PaddleOCR1.安装2.DEMO 五、PaddleOCR&#xff08;PyTorch移植版&#xff09;1.代码整理2.DEMO 六、TrOCR1.安装2.模型下载3.DEMO 七、GOT1.安装2.模型下载3…

机器学习(5):机器学习项目步骤(二)——收集数据与预处理

1. 数据收集与预处理的任务&#xff1f; 为机器学习模型提供好的“燃料” 2. 数据收集与预处理的分步骤&#xff1f; 收集数据-->数据可视化-->数据清洗-->特征工程-->构建特征集和数据集-->拆分数据集、验证集和测试集 3. 数据可视化工作&#xff1f; a. 作用&…

这款免费工具让你的电脑焕然一新,专业人士都在用

HiBit Uninstaller 采用单一可执行文件的形式,无需复杂的安装过程,用户可以即刻开始使用。这种便捷性使其成为临时使用或紧急情况下的理想选择。尽管体积小巧,但其功能却异常强大,几乎不会对系统性能造成任何负面影响。 这款工具的一大亮点是其多样化的功能。它不仅能够常规卸…

鸿蒙harmonyos next纯flutter开发环境搭建

公司app是用纯flutter开发的&#xff0c;目前支持android和iOS&#xff0c;后续估计也会支持鸿蒙harmonyos。目前谷歌flutter并没有支持咱们国产手机操作系统鸿蒙harmonyos&#xff0c;于是乎国内有个叫OpenHarmony-SIG的组织&#xff0c;去做了鸿蒙harmonyos适配flutter开发的…

实验2 网络测试命令的使用及对等网组建

实验2 网络测试命令的使用及对等网组建 一、实验目的 1. 熟悉常用网络测试命令的语法及其功能&#xff1b; 2. 掌握常用的网络故障分析及排除的方法&#xff1b; 3. 熟悉Windows中的网络组建及各参数的设置和基本意义。 4.如何在对等网中建立共享及访问对方的共享资源。 二、…

精通推荐算法31:行为序列建模之ETA — 基于SimHash实现检索索引在线化

1 行为序列建模总体架构 2 SIM模型的不足和为什么需要ETA模型 SIM实现了长周期行为序列的在线建模&#xff0c;其GSU检索单元居功至伟。但不论Hard-search还是Soft-search&#xff0c;都存在如下不足&#xff1a; GSU检索的目标与主模型不一致。Hard-search通过类目属性来筛选…

《深度学习》【项目】OpenCV 发票识别 透视变换、轮廓检测解析及案例解析

目录 一、透视变换 1、什么是透视变换 2、操作步骤 1&#xff09;选择透视变换的源图像和目标图像 2&#xff09;确定透视变换所需的关键点 3&#xff09;计算透视变换的变换矩阵 4&#xff09;对源图像进行透视变换 5&#xff09;对变换后的图像进行插值处理 二、轮廓检测…

集翼智能视频营销管理平台 丨OPENAIGC开发者大赛企业组AI创作力奖

在第二届拯救者杯OPENAIGC开发者大赛中&#xff0c;涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到&#xff0c;我们特意开设了优秀作品报道专栏&#xff0c;旨在展示其独特之处和开发者的精彩故事。 无论您是技术专家还是爱好者&#xff0c;希望能带给…

GreenPlum数开手册【语法篇】

GreenPlum数开手册 一、数据类型 1、基本数据类型 类型长度描述范围bigint8字节大范围整数-9223372036854775808 到 9223372036854775807smallint2字节小范围整数-32768到32767integer(int)4字节常用整数-2147483648 到 2147483647decimal可变长用户指定的精度&#xff0c;精…

服务运营 | 运营前沿:生成式AI改变医疗保健的运作方式

编者按 人工智能正在重塑医疗保健的运作方式&#xff0c;减少医生负担并优化病人的就医体验。从解答患者疑问到开发新药&#xff0c;人工智能正在快速革新医疗保健这一行业。编者团队此次将关注《哈佛商业评论》于2023年11月27日发布的文章《GenAI Could Transform How Health …

实验一 网络基础及仿真模拟软件Packet Tracer 入门

实验一 网络基础及仿真模拟软件Packet Tracer 入门 【实验目的】 一、认识 Packet Tracer 。 二、学习使用 Packet Tracer 进行拓扑的搭建。 三、学习使用 Packet Tracer 对设备进行配置&#xff0c;并进行简单的测试。 【实验内容和结果】 一、拖放设备和布置线缆 二、用…

国庆假节高速免费通行全攻略

关注▲洋洋科创星球▲一起成长&#xff01; 国庆节假期全国收费公路继续对7座以下&#xff08;含7座&#xff09;小型客车免收车辆通行费。 具体免费时段从 10月1日00&#xff1a;00开始 10月7日24&#xff1a;00结束 01 提前出发&#xff0c;免费离开&#xff1a; 如果你在…

HttpServletRequest简介

HttpServletRequest是什么&#xff1f; HttpServletRequest是一个接口&#xff0c;其父接口是ServletRequest&#xff1b;HttpServletRequest是Tomcat将请求报文转换封装而来的对象&#xff0c;在Tomcat调用service方法时传入&#xff1b;HttpServletRequest代表客户端发来的请…

数据结构:详解搜索二叉树

目录 一、搜索二叉树的概念 二、搜索二叉树的基本结构 三、搜索二叉树的插入 四、搜索二叉树的查找 五 、搜索二叉树的删除 一、搜索二叉树的概念 ⼆叉搜索树⼜称⼆叉排序树&#xff0c;它或者是⼀棵空树&#xff0c;或者是具有以下性质的⼆叉树&#xff1a; 若它的左子树…

每天五分钟深度学习PyTorch:如何使用GPU来跑深度学习算法模型?

本文重点 我们前面介绍pytorch的时候,我们提到过它可以使用GPU加速,那么如何才能完成GPU的加速呢?在pytorch中非常简单,我们只需要将数据计算,模型放到GPU上就行,这样就可以使用GPU来跑深度学习算法模型了。 如何判断我们的电脑是否支持GPU pytorch中关于GPU的一些相关…

[JavaEE] IP协议

目录 一、 IP协议 1.1 基本概念 1.2 协议头格式 1.3 特殊IP 二、 地址管理 2.1 网段划分 2.2 CIDR(Classless Interdomain Routing) 2.3 私有IP地址和公网IP地址 2.4 NAT(Network Address Translation)-网络地址转换 2.5 路由选择 三、数据链路层 3.1 认识以太网 3…

嵌入式Linux系统TF卡热插拔检测问题

一、背景介绍 项目上使用linux系统&#xff0c;运行主控是君正T41&#xff0c;遇到一个系统无法识别TF卡的问题&#xff0c;经过一番探索最终成功解决。感觉挺有意思的&#xff0c;记录下分析和解决的过程。 二、现象描述 插入TF卡后系统无任何反应&#xff0c;也没有生成 /…

工业缺陷检测——Windows 10本地部署AnomalyGPT工业缺陷检测大模型

0. 引言 在缺陷检测中&#xff0c;由于真实世界样本中的缺陷数据极为稀少&#xff0c;有时在几千甚至几万个样品中才会出现一个缺陷数据。因此&#xff0c;以往的模型只需在正常样本上进行训练&#xff0c;学习正常样品的数据分布。在测试时&#xff0c;需要手动指定阈值来区分…

Java零工市场小程序如何改变自由职业者生活

如今&#xff0c;自由职业者越来越多&#xff0c;他们需要找到合适的工作机会&#xff0c;Java零工市场小程序&#xff0c;为自由职业者提供了一个方便、快捷的寻找工作机会的方式&#xff0c;这样一来&#xff0c;改变了自由职业者找寻工作的方式&#xff0c;也提高了他们的收…