《剑指offer》(4)二叉树篇

二叉树深度有两种递归思路:

(1)递归返回当前的深度,当root是空时,返回0

(2)将当前深度和节点一起传入递归,设置全局变量,每经过一个节点就更新全局变量的值。

 方法一:

class TreeNode:

    def __init__(self,val):

        self.val = val

        self.left = None

        self.right = None

class Solution:

    def TreeDepth(self , pRoot: TreeNode) -> int:

        if pRoot is None:

            return 0

        l = self.TreeDepth(pRoot.left)

        r = self.TreeDepth(pRoot.right)

        return max(l,r)+1

方法二:

class TreeNode:

    def __init__(self,val):

        self.val = val

        self.left = None

        self.right = None

class Solution:

    def TreeDepth(self , pRoot: TreeNode) -> int:

        ans = 0

        def f(node,cnt):

            if node is None:

                return

            cnt += 1

            nonlocal ans

            ans = max(ans,cnt)

            f(node.left,cnt)

            f(node.right,cnt)

        f(pRoot,0)

        return ans

class Solution:

    def Mirror(self , pRoot: TreeNode) -> TreeNode:

        if pRoot is None:

            return pRoot #空就返回空

        #交换左右子树

        pRoot.left,pRoot.right = pRoot.right,pRoot.left

        #递归左右子树

        self.Mirror(pRoot.left)

        self.Mirror(pRoot.right)

        #返回根节点

        return pRoot

class Solution:

    def PrintFromTopToBottom(self , root: TreeNode) -> List[int]:

        #层序遍历

        import collections

        ans = []

        if root is None:

            return []

        #把root写入队列里

        q = collections.deque([root])

        #当队列中存在元素时

        while q:

            for _ in range(len(q)):

                node = q.popleft() #出队

                ans.append(node.val) #加入到答案中

                if node.left:  #遍历左子树

                    q.append(node.left)

                if node.right: #遍历右子树

                    q.append(node.right)

        return ans

class Solution:

    def IsBalanced_Solution(self , pRoot: TreeNode) -> bool:

        #递归左子树和右子树的深度,如果深度差超过1,就返回-1,遇到-1就直接退出

        def f(node):

            if node is None:

                return 0

            l = f(node.left)

            if l == -1:

                return -1

            r = f(node.right)

            if r == -1 or abs(l-r) > 1:

                return -1

            return max(l,r)+1

        return f(pRoot) != -1

 

class Solution:

    #判断两颗二叉树是否相等(镜像)

    def isSame(self,l,r):

        if l is None or r is None:

            return l == r

        return l.val == r.val and self.isSame(l.left,r.right) and self.isSame(l.right,r.left)

    def isSymmetrical(self , pRoot: TreeNode) -> bool:

        if pRoot is None:

            return True

        return self.isSame(pRoot.left,pRoot.right)

 

class Solution:

    def rightSideView(self, root: Optional[TreeNode]) -> List[int]:

        #设置全局变量记录答案,把当前深度和答案长度对比,如果相等,就可以记入答案

        #先遍历右子树,再遍历左子树

        ans = []

        def f(node,cnt):

            if node is None:

                return

            if len(ans) == cnt:

                ans.append(node.val)

            f(node.right,cnt+1)

            f(node.left,cnt+1)

        f(root,0)

        return ans

 

方法一:前序遍历

class Solution:

    def isValidBST(self, root: Optional[TreeNode],left = -inf,right = inf) -> bool:

        if root is None:

            return True

        x = root.val #取值

        return  left < x < right and self.isValidBST(root.left,left,x) and self.isValidBST (root.right, x, right) #判断该值的范围and该节点左右子树是不是二叉搜索树

方法二:中序遍历(得到一个严格递增的数组)

class Solution:

    pre = -inf

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

        #如果是空直接返回True

        if root is None:

            return True

        #遍历左子树,如果左子树是False,就返回False

        if not self.isValidBST(root.left):

            return False

        #记录下当前节点值

        x = root.val

        #让节点值和前一个值比对,如果小于等于前一个值,就False

        if x <= self.pre:

            return False

        #更新前一个节点值

        self.pre = x

        #递归右子树

        return self.isValidBST(root.right)

 方法三:后序遍历

class Solution:

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

        def f(root):

            #如果是空返回inf,-inf(True)

            if root is None:

                return inf,-inf

            #取左右子树的最小值,最大值

            l_min,l_max = f(root.left)

            r_min,r_max = f(root.right)

            #取当前节点值

            x = root.val

            #当前节点如果小于左边的最大值,或者大于右边的最小值,返回-inf,inf(Fasle)

            if x <= l_max or x >= r_min:

                return -inf,inf

            #返回左边的最小值,右边的最大值

            return min(l_min,x),max(r_max,x)

        return f(root)[1] != inf #如果最后收回来是inf,那就False

class Solution:

    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':

        #如果当前节点是空,或者就是p,q就返回当前节点

        if root is None or root is p or root is q:

            return root

        #递归左右子树

        left = self.lowestCommonAncestor(root.left,p,q)

        right = self.lowestCommonAncestor(root.right,p,q)

        #如果左右子树都有,就返回当前节点

        if left and right:

            return root

        #如果在左子树,就返回左子树

        if left:

            return left

        #如果在右子树,或者左右都没有,就返回right(可能是空)

        return right

class Solution:

    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':

        #取当前节点的值

        x = root.val

        #如果q,p的值都大于x,那就在都在右子树中,递归右子树

        if q.val > x and p.val > x:

            return self.lowestCommonAncestor(root.right,p,q)

        #如果都小于x,就递归左子树

        if q.val < x and p.val < x:

            return self.lowestCommonAncestor(root.left,p,q)

        #其他情况:q,p是当前节点,或者p,q各自在左右子树中,返回当前节点

        return root

#层序遍历二叉树,偶数层反转

class Solution:

    def Print(self , pRoot: TreeNode) -> List[List[int]]:

        # 层序遍历的时候,把偶数层反转

        ans  = []

        if pRoot is None:

            return []

        import collections

        q = deque([pRoot])

        is_odd = True

        while q:

            res = []

            for _ in range(len(q)):

                x = q.popleft()

                res.append(x.val)

                if x.left: q.append(x.left)

                if x.right: q.append(x.right)

            if is_odd:

                ans.append(res)

                is_odd = False

            else:

                ans.append(res[::-1])

                is_odd = True

        return ans

#层序遍历

class Solution:

    def Print(self , pRoot: TreeNode) -> List[List[int]]:

        #层序遍历

        if pRoot is None:

            return []

        import collections

        q = collections.deque([pRoot])

        ans = []

        while q:

            res = []

            for _ in range(len(q)):

                x = q.popleft()

                res.append(x.val)

                if x.left: q.append(x.left)

                if x.right: q.append(x.right)

            ans.append(res)

        return ans

#二叉搜索树的中序遍历是一个严格递增序列,中序遍历二叉树后,选择第k-1个值输出

class Solution:

    def KthNode(self , proot: TreeNode, k: int) -> int:

        # 二叉搜索树的中序遍历是严格递增序列

        res = []

        if proot is None or k == 0: #注意特殊情况

            return -1

        def f(node): #中序遍历

            if node is None:

                return

            f(node.left)

            nonlocal res

            res.append(node.val)

            f(node.right)

        f(proot)

        if len(res) < k: #特殊情况

            return -1

        else:

            return res[k-1]

class TreeNode:

    def __init__(self, x):

        self.val = x

        self.left = None

        self.right = None

class Solution:

    def reConstructBinaryTree(self , preOrder: List[int], vinOrder: List[int]) -> TreeNode:

        #从前序遍历中找到当前的根节点,然后划分中序遍历中的左右子树。将左子树的前序和中序递归得到左子树,右子树的前序和中序递归,得到右子树。

        #判断错误情况

        if len(preOrder) == 0:

            return None

        #构建根节点

        root = TreeNode(preOrder[0])

        #找到根节点在中序中的下标

        index = vinOrder.index(preOrder[0])

        #左子树的前序和中序

        l_pre = preOrder[1:index+1]

        l_vin = vinOrder[:index]

        root.left = self.reConstructBinaryTree(l_pre,l_vin)

        #右子树的前序和中序

        r_pre = preOrder[index+1:]

        r_vin = vinOrder[index+1:]

        root.right = self.reConstructBinaryTree(r_pre,r_vin)

        return root

class Solution:

    def isSubStructure(self, pRoot1: TreeNode, pRoot2: TreeNode) -> bool:

        if pRoot2 is None or pRoot1 is None: #异常判断

            return False

        #设置全局变量记录当前比对结果

        status = False

        #遍历树A和B的根节点比较

        def dfs(a):

            if a is None: return

            nonlocal status

            if a.val == pRoot2.val : status = check(a,pRoot2) #遇到相等的节点就check一下

            if a.left: dfs(a.left)

            if a.right: dfs(a.right)

        def check(a,b):

            if b is None: #如果比对之后,B是空,那说明之前比对的都符合子树

                return True

            if a is None: #如果比对之后A是空,但是B不是空,那就说明不符合

                return False

            if a.val != b.val: #A和B的数据不一样,说明不符合

                return False

            return check(a.left,b.left) and check(a.right,b.right)

        dfs(pRoot1)

        return status

class Solution:

    def VerifySquenceOfBST(self , sequence: List[int]) -> bool:

        #先判断是否为空

        if len(sequence) == 0:

            return False

        #递归树的左右子树,判断其是不是二叉搜索树

        def check(sequence):

            #如果只有一个节点了,那就返回True

            if len(sequence) <= 1:

                return True

            #确定根节点

            root = sequence[-1]

            #确定左右子树的分界,因为值各不相等,如果遍历到了大于等于树的值,则遍历到了根或者右子树

            ind = 0

            while ind < len(sequence):

                if sequence[ind] >= root:

                    break

                ind += 1

            #查询左右子树中是否有不符合条件的

            a = [j for j in sequence[:ind] if j > root]

            b = [j for j in sequence[ind:-1] if j < root]

            if a or b:

                return False

            #递归判断左右子树

            return check(sequence[:ind]) and check(sequence[ind:-1])

        #返回判断的结果

        return check(sequence)

 

class Solution:

    def hasPathSum(self , root: TreeNode, sum: int) -> bool:

        # 如果遍历到了空,就返回fasle

        if root is None:

            return False

        #当遍历到叶子节点的时候,当前节点的值等于sum,就返回True

        if not root.left and not root.right and sum == root.val:

            return True

        #遍历左右子树,并且把sum-root.val当做下一次的sum传入

        return self.hasPathSum(root.left,sum-root.val) or self.hasPathSum(root.right,sum-root.val)

class Solution:

    def FindPath(self , root: TreeNode, target: int) -> List[List[int]]:

        #判断异常情况

        if root is None:

            return []

        #全局变量存储答案

        ans = []

        def dfs(node,path): #将路径传入

            if node is None:

                return

            #路径保存当前节点的值

            path.append(node.val)

            #遇到叶子节点而且路径内的值与目标相等

            if not node.left and not node.right and sum(path) == target:

                nonlocal ans

                ans.append(path.copy()) #路径存入答案(用copy存,否则之后会改变)

            #递归左右子树

            dfs(node.left,path)

            dfs(node.right,path)

            #遍历完该路径后,恢复现场

            path.pop()

        dfs(root,[])

        return ans

class Solution:

    def FindPath(self , root: TreeNode, s: int) -> int:

        if root is None:

            return 0

        ans = 0

#第一层递归,遍历每个节点

        def func(root):

            if root is None:

                return

            dfs(root,s,[])

            func(root.left)

            func(root.right)

#第二层循环,检查以node为根节点的树中有没有路径

        def dfs(node,target,path):

            if node is None:

                return

            path.append(node.val)

            if sum(path) == target: #不需要走到叶子节点,相等就直接添加答案

                nonlocal ans

                ans += 1

            dfs(node.left,target,path)

            dfs(node.right,target,path)

            path.pop()

        func(root)

        return ans          

class Solution:

    head = None #记录头结点

    pre = None #记录当前节点的前一个节点

    def Convert(self , pRootOfTree ):

        #二叉搜索树中序遍历是一个有序表,当遍历到叶子时,改变左右指针

        if pRootOfTree is None:

            return None

        #先搜索左边

        self.Convert(pRootOfTree.left)

        #如果前置是空,初始化pre和head

        if not self.pre:

            self.head = pRootOfTree

            self.pre = pRootOfTree

        else:

#左指针是指向小节点,有指针指向大节点

            self.pre.right = pRootOfTree #前一个节点的值一定小于当前节点,用右指针指

            pRootOfTree.left = self.pre #将当前节点的左指针指向pre

            self.pre = pRootOfTree #更新pre的值

        self.Convert(pRootOfTree.right)

        return self.head

class Solution:

    def GetNext(self, pNode):

        #分成情况讨论:是否有右孩子?自己是左or右or根?如果自己是右,判断在左子树还是在右子树

        #情况一:有右孩子,取右孩子最左边的左孩子

        if pNode.right:

            p = pNode.right

            while p.left:

                p = p.left

            return p

        else:

            #情况二:没有右孩子,且自己是左孩子,取父亲节点

            if pNode.next and pNode.next.left == pNode:

                return pNode.next

            if not pNode.next: #没有右孩子,还没有父亲节点,那根节点就是最后一个

                return None

            #情况三:没有右孩子,且自己是右孩子

            else:

                pre = None

                #寻找根节点

                while pNode.next:

                    pre = pNode

                    pNode = pNode.next

                #在左子树中,返回根节点

                if pNode.left == pre:

                    return pNode

                else: #在右子树中,返回空

                    return None

import collections

class Solution:

    def Serialize(self, root):

        #层序遍历序列化二叉树

        ans = []

        if root is None:

            return ''

        q = collections.deque([root])

        while q:

            for _ in range(len(q)):

                x = q.popleft()

                if x: #如果x不是空

                #将该元素写入,加空格为了分割数字

                    ans.append(str(x.val)+' ')

                    if x.left : q.append(x.left)

                    else: q.append(None) #没有左子树就把空放进去

                    if x.right : q.append(x.right)

                    else: q.append(None)

                else: #如果是空

                    ans.append('#'+' ') #将‘#’填入

        return ''.join(ans)

    def Deserialize(self, s):

        #反序列化的时候,依旧按照入队出队,把根节点入队,然后取s中的两个数,如果不是'#'创建左子树并入队,i每次增加2

        if len(s) == 0:

            return None

        #消除前后空格后按照空格分割成list

        s = s.strip().split(' ')

        root = TreeNode(int(s[0]))

        q = collections.deque([root])

        i = 1

        while i < len(s)-1:

            node = q.popleft()

            a,b = s[i],s[i+1]

            if a != '#':

                node.left = TreeNode(int(s[i]))

                q.append(node.left)

            if b != '#':

                node.right = TreeNode(int(s[i+1]))

                q.append(node.right)

            i +=2

        return root

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高速公路巡检无人机,为何成为公路巡检的主流工具

随着无人机技术的不断发展&#xff0c;无人机越来越多地应用于各个领域。其中&#xff0c;在高速公路领域&#xff0c;高速公路巡检无人机已成为公路巡检的得力助手。高速公路巡检无人机之所以能够成为公路巡检中的主流工具&#xff0c;主要是因为其具备以下三大特性。 一、高速…

iOS——Block回调

先跟着我实现最简单的 Block 回调传参的使用&#xff0c;如果你能举一反三&#xff0c;基本上可以满足了 OC 中的开发需求。已经实现的同学可以跳到下一节。 首先解释一下我们例子要实现什么功能&#xff08;其实是烂大街又最形象的例子&#xff09;&#xff1a; 有两个视图控…

Vector - CAPL - 诊断模块函数(连接管理)

CanTpCreateConnection - 创建TP连接 功能&#xff1a;使用给定的地址模式&#xff08;add人Mode&#xff09;创建新连接&#xff0c;可用于诊断数据的收发。 说明&#xff1a;无法更改已有连接的寻址模式&#xff1b;如果确实有需要&#xff0c;可以关闭当前连接后再创建一个…

复习之linux系统的引导修复

启动Linux系统时&#xff0c;需要先通电&#xff0c;接着系统会自动进行bios初始化&#xff0c;对硬件进行检测并初始化硬件时钟&#xff0c;之后就进入了 Linux系统引导过程。Linux系统引导过程的具体内容和引导修复方法将在下文中进行详细介绍。由于我们在引导修复时需要利用…

Mac 终端快捷键设置:如何给 Mac 中的 Terminal 设置 Ctrl+Alt+T 快捷键快速启动

Mac 电脑中正常是没有直接打开终端命令行的快捷键指令的&#xff0c;但可以通过 commandspace 打开聚焦搜索&#xff0c;然后输入 ter 或者 terminal 全拼打开。但习惯了 linux 的同学会觉得这个操作很别扭。于是我们希望能通过键盘按键直接打开。 操作流程如下&#xff1a; 1…

LangChain+ChatGLM整合LLaMa模型(二)

开源大模型语言LLaMa LLaMa模型GitHub地址添加LLaMa模型配置启用LLaMa模型 LangChainChatGLM大模型应用落地实践&#xff08;一&#xff09; LLaMa模型GitHub地址 git lfs clone https://huggingface.co/huggyllama/llama-7b添加LLaMa模型配置 在Langchain-ChatGLM/configs/m…

16.M端事件和JS插件

16.1移动端 移动端也有自己独特的地方 ●触屏事件touch (也称触摸事件)&#xff0c;Android 和I0S都有。 ●touch对象代表一个触摸点。触摸点可能是一根手指&#xff0c;也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。 ●常见的触屏事件如下: …

VS2017中Qt工程报错:无法解析的外部符号 __imp_CommandLineToArgvW,该符号在函数 WinMain 中被引用

工程报错:无法解析的外部符号 __imp_CommandLineToArgvW&#xff0c;该符号在函数 WinMain 中被引用 解决方法&#xff1a; 在输入的附加依赖项中增加 shell32.lib

装饰器模式(Decorator)

装饰器模式是一种结构型设计模式&#xff0c;用来动态地给一个对象增加一些额外的职责。就增加对象功能来说&#xff0c;装饰器模式比生成子类实现更为灵活。装饰器模式的别名为包装器(Wrapper)&#xff0c;与适配器模式的别名相同&#xff0c;但它们适用于不同的场合。 Decor…

《长安的荔枝》阅读笔记

《长安的荔枝》阅读笔记 2023年6月9号在杭州的小屋读完&#xff0c;作者以“一骑红尘妃子笑”的典故&#xff0c;想象拓展出来的荔枝使李善德&#xff0c;为了皇帝要求在贵妃寿辰&#xff0c;六月一号那天要吃到10斤的荔枝。需要从广州运送到长安即如今的西安。本来以为这个差事…

Elasticsearch:如何将整个 Elasticsearch 索引导出到文件 - Python 8.x

在实际的使用中&#xff0c;我们有时希望把 Elasticsearch 的索引保存到 JSON 文件中。在之前&#xff0c;我写了一篇管如何备份 Elasticsearch 索引的文章 “Elasticsearch&#xff1a;索引备份及恢复”。在今天&#xff0c;我们使用一种 Python 的方法来做进一步的探讨。你可…

RabbitMQ安装说明文档-v2.0

rabbitmq安装 说明&#xff1a;请使用资料里提供的CentOS-7-x86_64-DVD-1810.iso 安装虚拟机. 1. 安装依赖环境 在线安装依赖环境&#xff1a; yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c kernel-devel m4 ncurses-devel …

瞄准产业应用,大模型加持的深兰科技AI虚拟数字人落地业务场景

伴随ChatGPT的问世&#xff0c;在技术与商业运作上都日渐发展成熟的AI数字人产业正持续升温。 目前的AI数字人不仅拥有超高“颜值”&#xff0c;同时还拥有更为丰富的、细腻的表情和动作。更有甚者&#xff0c;AI数字人已经具备自定义构建知识图谱、自主对话、不断学习成长的能…

C++类与对象(下)

目录 初始化列表单参数构造函数的隐式类型转换 static成员友元友元函数友元类 内部类匿名对象了解&#xff1a;编译器优化练习题 初始化列表 构造函数体中的语句只能将其称为赋初值&#xff0c;而不能称作初始化。因为初始化只能初始化一次&#xff0c;而构造函数体内可以多次…

【论文】【生成对抗网络五】Wasserstein GAN (WGAN)

【题目、作者】&#xff1a; 紫色&#xff1a;要解决的问题或发现的问题 红色&#xff1a;重点内容 棕色&#xff1a;关联知识&#xff0c;名称 绿色&#xff1a;了解内容&#xff0c;说明内容 论文地址&#xff1a; 论文下载 本篇文章仅为原文翻译&#xff0c;仅作参考。…

jar命令的安装与使用

场景&#xff1a; 项目中经常遇到使用WinR软件替换jar包中的文件&#xff0c;有时候存在WinRAR解压替换时提示没有权限&#xff0c;此时winRAR不能用还有有什么方法替换jar包中的文件。 方法&#xff1a; 使用jar命令进行修改替换 问题&#xff1a; 执行jar命令报错jar 不…

[用go实现解释器]笔记1-词法分析

本文是《用go实现解释器》的读书笔记 ​ https://malred-blog​malred.github.io/2023/06/03/ji-suan-ji-li-lun-ji-shu-ji/shi-ti/go-compile/yong-go-yu-yan-shi-xian-jie-shi-qi/go-compiler-1/#toc-heading-6http://个人博客该笔记地址 ​github.com/malred/malanghttp:/…

Ubuntu网络设置之固定IP详解

尊敬的家人们&#xff0c;欢迎观看我的文章&#xff01;今天&#xff0c;我们将为您介绍Ubuntu22.04操作系统中固定IP的设置方法&#xff0c;帮助您更好地管理网络连接并提高网络稳定性。 什么是固定IP&#xff1f; 在网络中&#xff0c;IP地址是设备在网络上的唯一标识。通常…

Linux6.31 Kubernetes 二进制部署

文章目录 计算机系统5G云计算第二章 LINUX Kubernetes 部署一、二进制搭建 Kubernetes v1.201.操作系统初始化配置2.部署 etcd 集群3.Kubernetes 集群架构与组件4.部署 Master 组件5.部署 Worker Node 组件6.部署 CNI 网络组件——部署 flannel1&#xff09;K8S 中 Pod 网络通信…

lc1074.元素和为目标值的子矩阵数量

创建二维前缀和数组 两个for循环&#xff0c;外循环表示子矩阵的左上角&#xff08;x1,y1&#xff09;&#xff0c;内循环表示子矩阵的右下角&#xff08;x2,y2&#xff09; 两个for循环遍历&#xff0c;计算子矩阵的元素总和 四个变量&#xff0c;暴力破解的时间复杂度为O(…