代码随想录27期|Python|Day18|二叉树|路径总和iii|找树左下角的值|从中序与后序遍历序列构造二叉树

 第一次刷的时候题解都不是精简版

 513. 找树左下角的值 - 力扣(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 findBottomLeftValue(self, root):""":type root: TreeNode:rtype: int"""res = 0queue = collections.deque()queue.append(root)while queue:size = len(queue)for i in range(size):cur = queue.popleft()# 当索引是队列的第一个值(也就是下一层最先被加入的节点)if i == 0:res = cur.valif cur.left:queue.append(cur.left)if cur.right:queue.append(cur.right)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 findBottomLeftValue(self, root):""":type root: TreeNode:rtype: int"""# 深度递归 + 回溯# 用self.定义全局变量self.max_depth = float('-inf')self.res = 0self.traversal(root, 0)return self.resdef traversal(self, node, depth):  # depth 接受的是当前层的深度# 如果当前节点是叶子节点,判断当前深度是否是最大if not node.left and not node.right:# 更新最大深度if depth > self.max_depth:self.max_depth = depthself.res = node.valif node.left:depth += 1  # 深度 + 1self.traversal(node.left, depth)  # 此处传入的深度是子节点的深度depth -= 1  # 深度回溯 - 1if node.right:depth += 1self.traversal(node.right, depth)depth -= 1

 112. 路径总和 - 力扣(LeetCode)

重点是递归的返回值,传入参数,以及回溯部分的修改。

首先确定返回值,由于这一题不是遍历整个二叉树,而是找到满足条件的值就直接返回,所以返回值是bool。传入参数是需要一直更新和回溯的,这里是目标值和节点

在递归中,我们自顶向下用目标值分别减去路径上的节点值,所以在递归结束之后,需要把这个值加回来。

还需要注意:在回溯到子节点返回True的时候,意味着这条路径是可行的,但是这个True只能返回到上一级的递归函数体里面。要返回到根节点的话需要一直向上返回到root,所以在左右子节点处理的时候我们在接受到底层传进来的True的时候需要再往上返回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 hasPathSum(self, root, targetSum):""":type root: TreeNode:type targetSum: int:rtype: bool"""if not root:return Falsereturn self.traversal(root, targetSum - root.val)# Step 1:传入参数(当前节点,目标值扣除当前节点值的结果)def traversal(self, node, count):# Step 2:终止条件# 1、count减到0,这条路径可行,返回给上一级if not node.left and not node.right and count == 0:return True # 2、count没减到0,这条路径标记为false,返回给上一级if not node.left and not node.right:return False# Step 3:中间处理# 左节点 if node.left:count -= node.left.val  # 先扣除左子节点的值# 如果子节点遍历结果是True,那么这条路径有效,继续返回给上一级if self.traversal(node.left, count): return Truecount += node.left.val  # 回溯返还扣除的值# 右节点if node.right:count -= node.right.valif self.traversal(node.right, count): return Truecount += node.right.valreturn False

 113. 路径总和 II - 力扣(LeetCode)

本题在上一题的基础上要求返回全部满足条件的路径。

递归法

需要注意返回值:在本题中,由于设置的是全局变量,所以在递归函数中只需要对于变量进行更新,不需要有返回值,所以是return 即可。

另外本题可以学习如何使用Python类中的全局变量。

# 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 __init__(self):# 自定义全局变量保存结果和当前遍历的路径点self.res = []self.path = []# Step 1:确定返回值和参数# 由于是对于全局变量进行修改所以不需要返回值def traversal(self, node, count):# Step 2:确定终止条件# 当前节点是叶子节点,且count被减到0if not node.left and not node.right and count == 0:self.res.append(self.path[:])  # 满足条件的path全部保存return # 当前节点是叶子节点,但是不满足条件,不修改全局变量直接返回if not node.left and not node.right:return # Step 3:每次递归处理# 左节点if node.left:# 先加入路径点self.path.append(node.left.val)# count值减去左节点count -= node.left.val# 进入新的递归self.traversal(node.left, count)# count回溯count += node.left.val# 路径点回溯self.path.pop()# 右节点(同理)if node.right:self.path.append(node.right.val)count -= node.right.valself.traversal(node.right, count)count += node.right.valself.path.pop()return def pathSum(self, root, targetSum):""":type root: TreeNode:type targetSum: int:rtype: List[List[int]]"""if not root:return []# root不是空节点,先放入path中self.path.append(root.val)# 从根节点开始递归,传入参数是已经减掉root值的self.traversal(root, targetSum - root.val)return self.res

 迭代法

迭代在于对于栈的构建。本题采用的是由节点和通向该节点的路径组成的元组,其中路径的类型为由节点值组成的list。

# 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 pathSum(self, root, targetSum):""":type root: TreeNode:type targetSum: int:rtype: List[List[int]]"""# 迭代if not root:return []res = []# 注意这个栈的内容:节点和到此节点路径stack = [(root, [root.val])]while stack:# Step 1:取出栈中元素node, path = stack.pop()# 判断当前节点是否是满足条件if not node.left and not node.right and sum(path) == targetSum:res.append(path) # 满足,加入res# Step 2:更新栈中的元素# 左节点if node.left:# 注意这里也需要按照(节点,路径)的元素加入栈stack.append((node.left, path + [node.left.val]))# path 是由值组成的数组,但是可能会出现空值的情况,所以用concatenate不是append# 右节点if node.right:stack.append((node.right, path + [node.right.val]))return res

 106. 从中序与后序遍历序列构造二叉树 - 力扣(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 buildTree(self, inorder, postorder):""":type inorder: List[int]:type postorder: List[int]:rtype: TreeNode"""# 用后序子树来判断是因为和后续取root逻辑一致if not postorder:return None# 取出root节点的值(后序的最后一位)root_val = postorder[-1]root = TreeNode(root_val)  # 创建根节点# Step 1:在中序数组里找到root的值,作为切割点root_index = inorder.index(root_val)# 全部采用左闭右开区间(循环不变量)# [0, root_index) root_index已经被切走了left_inorder = inorder[:root_index]# [root_index + 1, end]right_inorder = inorder[root_index + 1 :]# Step 2:切割后序数组# 这里使用的是长度# [0, len(左子树))left_postorder = postorder[:len(left_inorder)]# (len(左子树), -1]  :-1是因为root是post的最后一位,已经被取走了right_postorder = postorder[len(left_inorder): -1]# Step 3:递归root.left = self.buildTree(left_inorder, left_postorder)root.right = self.buildTree(right_inorder, right_postorder)return root

特别需要注意的是循环不变量(区间的开闭)。本题使用的是左闭右开。

105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode) 

 和上面的一样,但是在前序切片的时候是从1开始,到左子树长度+1处(右端点取不到)。

# 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 buildTree(self, preorder, inorder):""":type preorder: List[int]:type inorder: List[int]:rtype: TreeNode"""if not preorder:return Noneroot_val = preorder[0]root = TreeNode(root_val)root_index = inorder.index(root_val)left_inorder = inorder[:root_index]right_inorder = inorder[root_index + 1 : ]left_preorder = preorder[1 : len(left_inorder) + 1]right_preorder = preorder[len(left_inorder) + 1 : ]root.left = self.buildTree(left_preorder, left_inorder)root.right = self.buildTree(right_preorder, right_inorder)return root

第18天完结🎉

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

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

相关文章

【JavaSE】Java入门八(Object类详解)

object类 Java中Object类是所有类的父类,可以理解为他是最抽象的一个类型,就像混沌,Java所有类型都继承自它,所有对象(包括数组)都实现这个类的方法。非常重要,下面我来根据JDK官方文档来带大家…

2023最新整理软件测试常见面试题附答案

包含的模块: 本文分为十九个模块,分别是:软件测试 基础、liunx、MySQL、web测试、接口测试、APP测试 、管理工具、Python、性能测试、selenium、lordrunner、计算机网络、组成原理、数据结构与算法、逻辑题、人力资源需要的可以【点击文末小…

python画图【02】

完整代码 https://gitee.com/ihan1001 https://github.com/ihan1001/python-drawing import matplotlib.pyplot as plt import numpy as np #创建空白画笔 fig plt.figure(figsize(4,3),facecolorpink)#添加子画布 ax1 fig.add_subplot(2,2,1) ax2 fig.add_subplot(2,2,2) …

Eclipse_01_如何设置代码文件背景颜色为护眼沙绿色

设置方法 Window --> Preference 参考文档 参考文档 1

LoadRunner-Analysis

Analysis介绍 Analysis介绍 Analysis:用于产生性能测试报告;在Controller这里选择Analyze Results 标准差越大说明系统越不稳定 添加新图表: 如果要把另一个表合在一起:

自动化测试 (五) 读写64位操作系统的注册表

自动化测试经常需要修改注册表 很多系统的设置(比如:IE的设置)都是存在注册表中。 桌面应用程序的设置也是存在注册表中。 所以做自动化测试的时候,经常需要去修改注册表 Windows注册表简介 注册表编辑器在 C:\Windows\regedit…

在 WinForms DataGridView 中居中绘制图片的全面指南

在 WinForms DataGridView 中居中绘制图片的全面指南 引言 在现代的桌面应用程序中,用户界面的直观性和吸引力是至关重要的。Windows Forms (WinForms) 提供了丰富的控件来构建这样的界面,其中 DataGridView 是展示和操作数据的核心控件之一。本文将详细介绍如何在 WinForms…

uniapp-打包安卓APP流程

打包前所需要的配置 1. 图标配置 准备好对应的图标 在第一步选择该图标 然后点击自动生成所有图标 就会生成下面所有尺寸的图标 会自动存放至unpackage文件中 2. 启动页面配置 通用界面就是最基本的一个小图标加一个名称 自定义则是自己手动添加对应的启动图片 这里的图…

2023-南京荣耀Honor最新探访-OPEN DAY,实况记录!

前言 金九银十的秋招季缓缓落幕! 接完offer,博主也回归啦!有幸带着公开公平的心态,给大家分享一波南京荣耀总部的实况解密! 最基础的环境状况,有图有真相!~上图~ 民以食为天-南京荣耀食堂&…

C#中的协变和逆变

这两个都是只能使用在接口和委托上 个人理解: 协变:出参,让基类使用范围变大,将父类/基类当作子类一样使用 --为什么这样规定呢? 我的理解:真正实现的是子类,子类拥有所有的方法,却…

麒麟系统SP2 与昇腾300I芯片测试qwen7B模型记录

1. 查看系统版本 uname -a Linux localhost.localdomain 4.19.90-24.4.v2101.ky10.aarch64 #1 SMP Mon May 24 14:45:37 CST 2021 aarch64 aarch64 aarch64 GNU/Linux 2. 查看显卡 npu-smi info 前情提要: 官网给出支持昇腾910架构,刚好有300I资源…

java线程池执行任务时异常被吃掉

问题 今天在测试环境通过线程池执行任务时突然被中断,跟踪日志发现代码跑到一半后面的日志就不再打印,而且也没有任何异常堆栈信息,也就是说程序执行被中断了,后面反复尝试经排查发现是线程池使用不当导致。 测试验证 我们用线程…