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

news2024/11/18 13:37:48

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

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

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

相关文章

控制台窗口和powershell运行服务会卡住的解决办法

问题描述 在 windows 环境下开发的时候&#xff0c;使用 PowerShell 执行 python.exe test.py 等命令经常会出现程序会卡在不动的问题。这时候需要到控制台按一下回车程序才会继续往下执行。 解决办法 原因: 控制台开启了快速编辑模式的情况下&#xff0c;如果鼠标选中了文本…

弘扬“两弹一星”精神,勇攀科学技术高峰——道本科技商业大学党日活动圆满落幕

2023年8月2日&#xff0c;道本科技与商业大学携手举办了一场主题为“弘扬‘两弹一星’精神&#xff0c;勇攀科学技术高峰”的党日活动。本次活动旨在了解党领导下的中国核工业发展历程&#xff0c;传承和弘扬“两弹一星”精神&#xff0c;同时展示道本科技创新产品&#xff0c;…

【力扣】链表题目总结

文章目录 链表基础题型一、单链表翻转、反转、旋转1.反转链表2.反转链表II——反转部分链表3.旋转链表4.K个一组翻转链表5.反转偶数长度组的节点 二、删除单链表中的结点1.删除链表的结点2.删除未排序链表中的重复节点3.删除已排序链表中的重复元素I——重复元素只剩下一个4.删…

带你简单认识淘宝 API 接口,API接口适用场景和业务类型

淘宝 API 接口是为开发电商类应用程序而设计的一套完整的、跨浏览器、跨平台的接口规范。通过开放接口&#xff0c;开发者可以不改变现有系统&#xff0c;直接在原有系统上实现新功能。该规范于 2007 年发布&#xff0c;是目前业界唯一完整覆盖电商系统各相关业务领域的接口标准…

C语言假期作业 DAY 13

一、选择题 1、如果 x2014 &#xff0c;下面函数的返回值是&#xff08; &#xff09; int fun(unsigned int x) { int n 0; while(x 1) { n; x x | (x 1); } return n; } A: 20 B: 21 C: 23 D 25 答案解析 正确答案&#xff1a;C 这个作用是对整型中0的个数进行统计&…

安卓手机录屏怎么把小白点去掉?试试这种方法

随着安卓手机功能的不断升级&#xff0c;录屏已经成为了一项基本功能。然而&#xff0c;当我们录制完视频后&#xff0c;常常会发现视频中有许多小白点&#xff0c;影响了视频的美观度。那么&#xff0c;如何去除这些小白点呢&#xff1f;本文将为大家介绍几种简单易行的方法。…

Linux操作系统块设备参数调优

目录 一、队列深度 二、调度算法 三、预读量 四、I/O对齐 一、队列深度 队列深度决定了给块设备写I/O的最大并发数&#xff0c;对于Linux系统&#xff0c;默认值为128&#xff0c;一般情况下不建议用户修改此参数。用户可以使用cat命令查询当前块设备队列深度。 linux-ob3a…

Arthas GC日志-JVM(十八)

上篇文章说jvm的实际运行情况。 Jvm实际运行情况-JVM&#xff08;十七&#xff09; Arthas介绍 因为arthas完全是java代码写的&#xff0c;我们直接用命令启动&#xff1a; Java -jar arthas-boot.jar 启动成功后&#xff0c;选择我们项目的进程。 进入我们可用dashboard…

ATFX汇评:非农就业报告来袭,汇市或迎剧烈波动

ATFX汇评&#xff1a;美国非农就业报告每月发布一次&#xff0c;其中非农就业人口和失业率两项数据最受关注。7月季调后非农就业人口&#xff0c;将于今日20:30公布&#xff0c;前值为20.9万人&#xff0c;预期值20万人&#xff1b;7月失业率&#xff0c;同一时间公布&#xff…

文字转语音

键盘获取文字&#xff0c;转化为语音后保存本地 from win32com.client import Dispatch from comtypes.client import CreateObject from comtypes.gen import SpeechLib speakerDispatch(SAPI.SpVoice) speaker.Speak(请输入你想转化的文字) datainput(请输入&#xff1a;)#s…

【二等奖方案】Web攻击检测与分类识别赛题「机器学习」团队解题思路

2022 CCF BDCI 数字安全公开赛 赛题「Web攻击检测与分类识别」 地址&#xff1a;http://go.datafountain.cn/4Zj 机器学习战队 获奖方案 团队简介 我们团队由五名成员组成&#xff0c;对机器学习都非常感兴趣&#xff0c;同时在机器学习领域有着丰富的实战经验&#xff0c…

Teams Room视频会议室方案

需求背景&#xff1a; 适合在40平米的会议室参加Teams视频会议&#xff0c;会议桌周围可以坐20人&#xff0c;要求&#xff1a; 1&#xff0c;操作简单&#xff0c;一键入会Teams Room&#xff1b; 2&#xff0c;任何人带上自己的笔记本电脑&#xff0c;可以分享电脑画面&#…

uniapp 持续获取定位(登录状态下才获取)(不采用定时器)(任意页面都可监听定位改变)

基于上次文章做了优化和改良,保证在登录状态下才获取定位信息 uniapp 小程序实时且持续获取定位信息(全局设置一次)(单页面监听定位改变)(不采用定时器)_uniapp小程序定位_前端小胡兔的博客-CSDN博客本篇文章实现了uniapp 微信小程序实时获取定位信息,小程序打开即可持续获取定…

2023年我想开信用账户!融资融券开通佣金最低是多少?两融利率低至5%!

2023年融资融券开通佣金最低是多少&#xff1f;两融利率低至5%&#xff01; 随着科技的不断发展和金融市场的日益完善&#xff0c;2023年的融资融券市场将迎来更加便捷和低成本的交易方式。据悉&#xff0c;融资融券开通佣金最低仅为5%&#xff0c;且利率也将进一步降至5%左右。…

eeglab(自用)

目录 1.加载、显示数据 2.绘制脑电头皮图 3.绘制通道光谱图 4.预处理工具 5.ICA去除伪迹 5. 提取数据epoch 1.加载、显示数据 观察事件值(Event values)&#xff1a;该数据集中包含2400个事件&#xff0c;每个事件指定了EEG.event结构的字段Type(类型)、position(位置)和…

HCIP BGP选路规则总结

选路前提条件 多条BGP路由目标相同&#xff0c;且均可优(下一跳可达、同步关闭)&#xff0c;具有相同的优先级&#xff08;管理距离&#xff09;。 1、优选Preference_Value值最高的路由&#xff08;私有属性&#xff0c;仅本地有效&#xff09;。 不传递 权限最高属性 …

为什么vscode访问谷歌浏览器是显示白色????

1、我的代码没有错误: 2、访问谷歌浏览器就显示白色&#xff1f;&#xff1f;&#xff1f;是什么情况

【word中如何插入带圆圈的数字编号】

第一种方法 在插入菜单栏选择编号 输入需要插入的数字&#xff0c;并选择编号类型 即可成功创建一个圆圈数字编号 第二种方法 在输入原本的数字后&#xff0c;选中数字&#xff0c;点击开始菜单栏中的字 选择所需的符号点击确定 即可成功添加带圈文字&#xff0c;但此种…

C#使用EmguCV播放视频

目录 一、前言 1、简介 2、测试工程代码下载链接 3、EmguCV 库文件下载链接 二、工程环境配置 1、EmguCV控件添加引用 &#xff08;1&#xff09;窗口控件添加 &#xff08;2&#xff09;相关Dll文件添加添加引用 &#xff08;3&#xff09;工程运行基础文件夹添加 &a…

棱镜七彩正式加入龙蜥社区安全联盟(OASA)

近日&#xff0c;龙蜥社区安全联盟&#xff08;OASA&#xff09;正式成立&#xff0c;棱镜七彩成为该联盟成员单位。 龙蜥社区安全联盟是促进产业合作的非营利组织&#xff0c;致力于打造中立开放、聚焦操作系统信息安全的交流平台&#xff0c;推进龙蜥社区乃至整个产业安全生态…