代码随想录27期|Python|Day15|二叉树|层序遍历|对称二叉树|翻转二叉树

本文图片来源:代码随想录

层序遍历(图论中的广度优先遍历)

这一部分有10道题,全部可以套用相同的层序遍历方法,但是需要在每一层进行处理或者修改。

102. 二叉树的层序遍历 - 力扣(LeetCode)

层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。

需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。

 队列长度法

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        # 判断是不是空二叉树
        if not root:
            return []
        # 先把根节点放入队列
        queue = collections.deque([root])
        res = []
        # 然后逐层放入队列再弹出
        while queue:
            # 每层储存在level数组里
            level = []
            for _ in range(len(queue)):
                # 弹出根节点,存值
                cur = queue.popleft()
                level.append(cur.val)
                # 队列添加左右节点
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 每层走完
            res.append(level)
        return res

递归法

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        # 递归法
        levels = []
        self.helper(root, 0, levels)
        return levels

    def helper(self, node, level, levels):
        # 退出条件
        if not node:
            return
        # 当层数和levels的长度相等的时候,也就是满二叉树的时候,需要再加上一个新的层
        if len(levels) == level:
            levels.append([])
        levels[level].append(node.val)
        self.helper(node.left, level + 1, levels)
        self.helper(node.right, level + 1, levels)

107. 二叉树的层序遍历 II - 力扣(LeetCode)

只需要倒序输出即可,代码和上面102保持一致。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def levelOrderBottom(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        if not root:
            return []
        queue = collections.deque([root])
        res = []
        while queue:
            levels = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                levels.append(cur.val)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            res.append(levels)
        # 反向输出即可
        return res[::-1]

199. 二叉树的右视图 - 力扣(LeetCode)

只需要每次把levels最后一个也就是最右侧的节点赋值给res即可。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def rightSideView(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if not root:
            return []
        res = []
        queue = collections.deque([root])
        while queue:
            levels = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                levels.append(cur.val)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 只需要每次把levels最后一个也就是左右侧的节点赋值给res即可
            res.append(levels[-1])
        return res

637. 二叉树的层平均值 - 力扣(LeetCode)

只需要在求出每层的基础上求平均即可。

注意作除法之前需要类型转换为float。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def averageOfLevels(self, root):
        """
        :type root: TreeNode
        :rtype: List[float]
        """
        if not root:
            return []
        res = []
        queue = collections.deque([root])
        while queue:
            levels = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                levels.append(cur.val)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 需要强制类型转换为浮点数
            sum_ = float(sum(levels))
            len_ = float(len(levels))
            avg = sum_ / len_
            res.append(avg)
        return res

429. N 叉树的层序遍历 - 力扣(LeetCode)

只需要把children列表里的元素按照顺序取出即可。

"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children
"""

class Solution(object):
    def levelOrder(self, root):
        """
        :type root: Node
        :rtype: List[List[int]]
        """
        if not root:
            return []
        res = []
        queue = collections.deque([root])
        while queue:
            levels = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                levels.append(cur.val)
                # children按列表储存child
                for child in cur.children:
                    queue.append(child)
            res.append(levels)
        return res

 515. 在每个树行中找最大值 - 力扣(LeetCode)

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def largestValues(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]
        """
        if not root:
            return []
        res = []
        queue = collections.deque([root])
        while queue:
            level = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                level.append(cur.val)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 每层最大值赋值给res
            res.append(max(level))
        return res

116. 填充每个节点的下一个右侧节点指针 - 力扣(LeetCode)

"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=0, left=None, right=None, next=None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""

class Solution(object):
    def connect(self, root):
        """
        :type root: Node
        :rtype: Node
        """
        if not root:
            return root  # 注意这一题的返回值是根节点地址,相当于只在原链表的基础上做修改
        queue = collections.deque([root])
        while queue:
            level = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                # queue的下一个值其实就是next需要指向的地址
                # if _ < len(queue) - 1:
                #   cur.next = queue[0]
                level.append(cur)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 在每一层遍历
            for i in range(len(level) - 1):
                level[i].next = level[i + 1]
        return root

 117. 填充每个节点的下一个右侧节点指针 II - 力扣(LeetCode)

"""
# Definition for a Node.
class Node(object):
    def __init__(self, val=0, left=None, right=None, next=None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""

class Solution(object):
    def connect(self, root):
        """
        :type root: Node
        :rtype: Node
        """
        if not root:
            return root  # 注意这一题的返回值是根节点地址,相当于只在原链表的基础上做修改
        queue = collections.deque([root])
        while queue:
            level = []
            for _ in range(len(queue)):
                cur = queue.popleft()
                # queue的下一个值其实就是next需要指向的地址
                # if _ < len(queue) - 1:
                #   cur.next = queue[0]
                level.append(cur)
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 在每一层遍历
            for i in range(len(level) - 1):
                level[i].next = level[i + 1]
        return root    

104. 二叉树的最大深度 - 力扣(LeetCode)

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        # 广度优先
        if not root:
            return 0
        cnt = 0
        queue = collections.deque([root])
        while queue:
            # 构造一层的队列
            for _ in range(len(queue)):
                cur = queue.popleft()
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
            # 构造完加一
            cnt += 1
        return cnt

        # 递归法
        if not root:
            return 0
        else:
            left_height = self.maxDepth(root.left)
            right_height = self.maxDepth(root.right)
        return max(left_height, right_height) + 1

        # 精简递归
        return 0 if not root else max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1

111. 二叉树的最小深度 - 力扣(LeetCode)

找到第一个叶子节点就退出while。这里用到了flag标记。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def minDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        # 广度优先
        if not root:
            return 0
        cnt = 0
        queue = collections.deque([root])
        flag = 0
        while queue:
            # 构造一层的队列
            for _ in range(len(queue)):
                cur = queue.popleft()
                if cur.left:
                    queue.append(cur.left)
                if cur.right:
                    queue.append(cur.right)
                if not (cur.left or cur.right):
                    flag = 1
            cnt += 1
            # 构造完加一
            if flag:
                break
        return cnt

226. 翻转二叉树 - 力扣(LeetCode)

深度遍历

omg!baseline只需要上面的套模板即可实现!!这不神奇吗??!!

根据顺序做具体的微调

前序/后续

只需要在原来代码的基础上加上子节点的交换过程即可。

递归法里的写法:

root.left, root.right = root.right, root.left

 迭代法里的写法:

node = stack.pop()   
node.left, node.right = node.right, node.left

中序

需要注意中序在执行完交换之后原来的左节点是右节点,但是right指针指向的是原left节点,所以需要在两次递归的时候都要指向left

self.invertTree(root.left)
root.left, root.right = root.right, root.left
selfinvertTree(root.left)

广度遍历(层序遍历)

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def invertTree(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        # 层序遍历
        if not root:
            return root
        queue = collections.deque([root])
        while queue:
            for _ in range(len(queue)):
                node = queue.popleft()
                # 对于取出队列里的每一个节点交换左右子节点
                node.left, node.right = node.right, node.left
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
        return root

101. 对称二叉树 - 力扣(LeetCode)

递归

 思路是分别比较两个子树的内侧和外侧,然后将结果取交集返回中间节点。所以确定便利的顺序一定是后序遍历(最后一个确定中间节点)。

因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
    # 递归法
        if not root:
            return True
        return self.compare(root.left, root.right)
    def compare(self, left, right):
        """
        左----右----result
        空    空     True
        空    有     False
        有    空     False
        有 != 有     False
        有 == 有     True
        """
        if left == None and right == None:
            return True
        elif left == None and right != None:
            return False
        elif left != None and right == None:
            return False
        elif left.val != right.val:
            return False
        else:  # 此时已经说明left == right,需要再判断他们的子节点
            outside = self.compare(left.left, right.right)  # 外侧子节点
            inside = self.compare(left.right, right.left)  # 内侧子节点
        is_same = outside and inside  # 求交集
        return is_same

 层序遍历

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        # 层次法
        queue = collections.deque([root])
        while queue:
            level_val = []  # 只需要保存值
            for _ in range(len(queue)):
                node = queue.popleft()
                if node:
                    level_val.append(node.val)
                    queue.append(node.left)
                    queue.append(node.right)
                else:  # 空节点赋值为None
                    level_val.append(None)
            if level_val != level_val[::-1]:  # 倒序比较数组
                return False
        return True

队列或栈

关键:成对取出外侧和内侧节点进行比较。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        # 栈或队列(队列只要把栈改成队列,pop搞成popleft就可以了)
        if not root:
            return True
        stack = []
        stack.append(root.left)
        stack.append(root.right)
        while stack:
            left = stack.pop()
            right = stack.pop()
            if left == None and right == None:
                continue  # 注意在while里需要continue
            if left == None or right == None or left.val != right.val:
                return False
            stack.append(left.left)
            stack.append(right.right)
            stack.append(left.right)
            stack.append(right.left)
        return True

2个相关题

100. 相同的树 - 力扣(LeetCode)

两个树,如果采用层序遍历的方法最好把重复部分封装成一个整体的函数。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def isSameTree(self, p, q):
        """
        :type p: TreeNode
        :type q: TreeNode
        :rtype: bool
        """
        # 层次法
        queue1 = collections.deque([p])
        queue2 = collections.deque([q])
        while queue1 and queue2:
            if len(queue1) != len(queue2):
                return False
            level1 = self.get_level(queue1)
            level2 = self.get_level(queue2)
            if level1 != level2:
                return False
        return True

    def get_level(self, queue):
        level_val = []
        for _ in range(len(queue)):
            node = queue.popleft()
            if node:
                level_val.append(node.val)
                queue.append(node.left)
                queue.append(node.right)
            else:
                level_val.append(None)
        return level_val

 572. 另一棵树的子树 - 力扣(LeetCode)

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def isSubtree(self, root, subRoot):
        """
        :type root: TreeNode
        :type subRoot: TreeNode
        :rtype: bool
        """
        # 深度遍历+递归
        if not root:
            return False
        
        return self.check_is_same(root, subRoot) or self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)

    def check_is_same(self, root, subroot):
        if root == None and subroot == None:
            return True
        elif root == None or subroot == None or root.val != subroot.val:
            return False
        return self.check_is_same(root.left, subroot.left) and self.check_is_same(root.right, subroot.right)

第15天完结🎉

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++入门(浅谈类和对象)

1 命名空间 1-1命名空间的定义 定义命名空间的目的是为了不与标识符的名称进行冲突&#xff0c;命名空间中可以定义函数&#xff0c;变量&#xff0c;类型。 比如&#xff1a;这里的rand和strlens其实是函数&#xff0c;在命名空间中可以避免与全局作用域中的rand函数和strlen…

编程性能调优方案

微信公众号转载&#xff0c;关注微信公众号掌握更多技术动态 --------------------------------------------------------------- 一、字符串与集合性能优化 1.String 对象的实现 在 Java 语言中&#xff0c;Sun 公司的工程师们对 String 对象做了大量的优化&#xff0c;来节…

2024测试开发面试题完整版本(附答案)

目录 1. 什么是软件测试&#xff0c; 谈谈你对软件测试的了解 2. 我看你简历上有写了解常见的开发模型和测试模型, 那你跟我讲一下敏捷模型 3. 我看你简历上还写了挺多开发技能的, 那你给我讲讲哈希表的实现流程 4. 谈一谈什么是线程安全问题, 如何解决 5. 既然你选择走测…

Java_泛型

泛型类 认识泛型 所谓泛型指的是&#xff0c;在定义类、接口、方法时&#xff0c;同时声明了一个或者多个类型变量&#xff08;如&#xff1a;< E >&#xff09;&#xff0c;称为泛型类、泛型接口、泛型方法、它们统称为泛型。 作用:泛型提供了在编译阶段约束所能操作的…

f盘隐藏的文件夹怎么找出来?介绍几种有效方法

在计算机中&#xff0c;我们经常会遇到隐藏的文件或文件夹&#xff0c;在F盘中隐藏的文件夹也不例外。隐藏的文件夹可能是由系统生成的&#xff0c;或者是用户自行设定的隐私文件夹。无论是因为误操作还是出于其他原因&#xff0c;如果你想找出F盘中的隐藏文件夹&#xff0c;本…

壹[1],函数:ReadImage

C形式 LIntExport void ReadImage( HObject* Image, const HTuple& FileName); //参数1&#xff1a;读取的Image //参数2&#xff1a;图片地址//备注说明&#xff1a; //头文件&#xff1a;halconcpp/HOperatorSet.h //命名空间&#xff1a;namespace HalconCpp C#形式 …

perl脚本中使用eval函数执行可能有异常的操作

perl脚本中有时候执行的操作可能会引发异常&#xff0c;为了直观的说明&#xff0c;这里举一个json反序列化的例子&#xff0c;脚本如下&#xff1a; #! /usr/bin/perl use v5.14; use JSON; use Data::Dumper;# 读取json字符串数据 my $json_str join(, <DATA>); # 反…

SpringMVC的文件上传、多文件上传

概念&#xff1a;上传/下载应用 对于上传功能&#xff0c;我们在项目中是经常会用到的&#xff0c;比如用户注册的时候&#xff0c;上传用户头像&#xff0c;这个时候就会使用到上传的功能。而对于下载&#xff0c;使用场景也很常见&#xff0c;比如我们项目中有个使用说明是是…

如何提升数据结构方面的算法能力?

谈及为什么需要花时间学算法&#xff0c;我至少可以列举出三个很好的理由。 (1)性能&#xff1a;选择正确的算法可以显著提升应用程序的速度。仅就搜索来说&#xff0c;用二分查找替 换线性搜索就能为我们帶来巨大的收益。 (2)安全性&#xff1a;如果你选用了错误的算法&…

小小手表探索更多 好玩伴也是好帮手

华为儿童手表 5X 不仅是孩子的好玩伴&#xff0c;也是家长的好帮手。全能形态让小小手表探索更多&#xff0c;高清双摄记录美好&#xff0c;离线定位随时掌握&#xff0c;绿色纯净守护成长&#xff0c;让孩子享受科技带来的安全与乐趣。

vue3.0项目搭建

一、安装vue3脚手架 卸载vue2脚手架 npm uninstall -g vue-cli清除缓存 npm cache clen --force安装最新脚手架 npm install -g vue/cli查看脚手架版本 vue -V 二、构建项目 创建项目 vue create 项目名选择配置 自定义配置&#xff0c;回车 上下键选择Linter / Formatter&a…

【超图】SuperMap iClient3D for WebGL/WebGPU ——暴雪

作者&#xff1a;taco 时隔多年北京又开始降下了特大暴雪。身为打工人的你有没有居家办公呢&#xff1f;反正小编我是没有。既然没有借着暴雪的功劳居家办公&#xff0c;那就接着雪来输出一篇博客好了。基于SuperMap iClient3D for WebGL/WebGPU 实现暴雪仿真效果。 先来看下效…

今日最新版早安问候大全,身体健康,平安幸福!

1&#xff0e;只想用不打扰你的方式轻轻地告诉你&#xff0c;我在惦记你。只希望你看到这个短信的时候&#xff0c;嘴角泛起灿烂的一笑!让身边的人知道你是幸福的&#xff0c;看短信的&#xff0c;我在问候你啊。早安~ 2&#xff0e;晨曦在呼叫&#xff0c;鸟儿在鸣叫&#xff…

【Hive】——DDL(TABLE)

1 查询指定表的元数据信息 如果指定了EXTENDED关键字&#xff0c;则它将以Thrift序列化形式显示表的所有元数据。 如果指定了FORMATTED关键字&#xff0c;则它将以表格格式显示元数据。 describe formatted student&#xff1b;2 删除表 如果已配置垃圾桶且未指定PURGE&…

复杂填报逻辑的支持

复杂填报逻辑的支持 一般填报表应用场景分为两种&#xff1a; 旧数据的维护 现有数据存储中已有一些数据&#xff0c;需要人工在页面对数据进行修改维护。 新数据的采集。 现有数据存储中没有数据&#xff0c;需要人工页面填写录入数据。 简单的数据维护与采集&#xff0…

Mysql 的ROW_NUMBER() 和分区函数的使用 PARTITION BY的使用

Mysql 的ROW_NUMBER() 和分区函数的使用 PARTITION BY的使用 描述: 遇到了一个需求,需要查询用户id和计划id,但是人员id的是重复,我想把人员id去重,支取一个。自然而然的就想到了SELECT DISTINCT prj_plan.last_month_user,prj_plan.id FROM prj_funds_plan prj_plan 但是…

Linux arm架构下构建Electron安装包

上篇文章我们介绍 Electron 基本的运行开发与 windows 安装包构建简单流程&#xff0c;这篇文章我们从零到一构建 Linux arm 架构下安装包&#xff0c;实际上 Linux arm 的构建流程&#xff0c;同样适用于 Linux x86 环境&#xff0c;只不过需要各自的环境依赖&#xff0c;Linu…

java中,用函数对象表示策略

简而言之&#xff0c;函数指针的主要用途就是实现策略(Strategy)模式。 Java没有提供函数指针&#xff0c;但是可以用对象引用实现相同的功能。调用对象上的方法通常是执行该对象上某项操作。 在Java中&#xff0c;使用函数对象&#xff08;Function Object&#xff09;表示策…

Elasitcsearch--解决CPU使用率升高

原文网址&#xff1a;Elasitcsearch--解决CPU使用率升高_IT利刃出鞘的博客-CSDN博客 简介 本文介绍如何解决ES导致的CPU使用率升高的问题。 问题描述 线上环境 Elasticsearch CPU 使用率飙升常见问题如下&#xff1a; Elasticsearch 使用线程池来管理并发操作的 CPU 资源。…

Android--Jetpack--Navigation详解

须知少日拏云志&#xff0c;曾许人间第一流 一&#xff0c;定义 Navigation 翻译成中文就是导航的意思。它是谷歌推出的Jetpack的一员&#xff0c;其目的主要就是来管理页面的切换和导航。 Activity 嵌套多个 Fragment 的 UI 架构模式已经非常普遍&#xff0c;但是对 Fragmen…
最新文章