首页 > 其他分享 >二叉树递归解决问题刷题 (一)

二叉树递归解决问题刷题 (一)

时间:2024-08-06 23:24:28浏览次数:15  
标签:right return 递归 max self 二叉树 left root 刷题

遇到和深度相关的题目,可以用dfs递归遍历深度获取bfs结果来做

513. 找树左下角的值

如何找二叉树最底层最左边节点的值呢,就是dfs遍历深度,来获取,最后一层的第一个元素就是。

class Solution:
    def __init__(self):
        # 记录二叉树的最大深度
        self.maxDepth = 0
        # 记录 traverse 递归遍历到的深度
        self.depth = 0
        self.res = None

    def findBottomLeftValue(self, root: TreeNode) -> int:
        self.traverse(root)
        return self.res.val

    def traverse(self, root: TreeNode):
        if root is None:
            return
        # 前序遍历位置
        self.depth += 1
        if self.depth > self.maxDepth:
            # 到最大深度时第一次遇到的节点就是左下角的节点
            self.maxDepth = self.depth
            self.res = root
        self.traverse(root.left)
        self.traverse(root.right)
        # 后序遍历位置
        self.depth -= 1 

分解问题的思路解决二叉树回顾

确定问题的性质:首先,你需要明确你要解决的问题是什么。例如,是要查找某个值,还是要遍历整棵树,或者是计算某个特定属性(如深度或节点数)?

找到基本情况(Base Case):这是递归的停止条件。对于二叉树来说,基本情况通常是树为空(即节点为 null)。在这种情况下,你可以直接返回结果(例如,对于查找值的问题,返回 false)。

分解问题:将问题分解成更小的子问题。对于二叉树,通常你需要对左右子树分别进行相同的操作。举个例子,如果你要查找一个值,你需要在左子树和右子树中分别查找该值。

递归调用:对左右子树递归调用相同的函数,解决更小的子问题。然后根据子问题的结果合成最终的答案。

合成结果:根据左右子树的结果,合成最终的结果。例如,对于查找值的问题,只要任意一个子树找到该值,你就可以返回 true


二叉树序列化问题

什么样的序列化的数据可以反序列化出唯一的一棵二叉树

包含了空指针的信息,也只有前序和后序的遍历结果才能唯一还原二叉树,中序遍历结果做不到。以什么格式序列化和反序列化,这个完全由你决定。所谓的序列化不过就是把结构化的数据「打平」,本质就是在考察二叉树的遍历方式。 递归遍历方式有前序遍历,中序遍历,后序遍历;迭代方式一般是层级遍历。

若没有包含空指针的信息, 至少要得到前、中、后序遍历中的两种互相配合才能还原二叉树。

在递归遍历两棵子树之前写的代码就是前序遍历代码,


类似于判断镜像二叉树、翻转二叉树的问题,一般也可以用分解问题的思路,无非就是把整棵树的问题(原问题)分解成子树之间的问题(子问题)。

100. 相同的树

判断两棵树是否相同,可以分解为判断根节点是否相同,然后判断左右子树的节点是否都相同。 !! 就是把大的问题一步步拆成小的问题,

class Solution:
    def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
        if p is None and q is None:
            return True 
        if (p is None and q is not None) or (q is None and p is not None):
            return False 
        if p.val != q.val:
            return False 
        return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right) 

基本情况

  • 如果 pq 都为 None,则两棵树是相同的,返回 True
  • 如果只有一个为 None,而另一个不是,则两棵树不同,返回 False

值比较

  • 如果 pq 的值不同,则两棵树不同,返回 False

递归比较

  • 如果 pq 的值相同,则递归比较它们的左子树和右子树。如果左子树和右子树都相同,则这两棵树相同

二叉树的层序遍历模板

from collections import deque

def levelOrderTraverse(root):
    if root is None:
        return
    q = deque()
    q.append(root)
    # 记录当前遍历到的层数(根节点视为第 1 层)
    depth = 1

while q:
    sz = len(q) #sz是size的简称
    for i in range(sz):
        cur = q.popleft() #从q中把第一层的数字移除出去。
        # 访问 cur 节点,同时知道它所在的层数
        print(f"depth = {depth}, val = {cur.val}")

        # 把 cur 的左右子节点加入队列
        if cur.left is not None:
            q.append(cur.left)
        if cur.right is not None:
            q.append(cur.right)
    depth += 1

所有的二叉树题目都不逃脱二叉树层序遍历模板和深度遍历模板

用dfs获得bfs结果 前序遍历

class Solution:
    res = []

    def levelTraverse(self, root):
        if root is None:
            return self.res
        # root 视为第 0 层
        self.traverse(root, 0)
        return self.res

    def traverse(self, root, depth):
        if root is None:
            return
        # 前序位置,看看是否已经存储 depth 层的节点了
        if len(self.res) <= depth:
            # 第一次进入 depth 层
            self.res.append([])
        # 前序位置,在 depth 层添加 root 节点的值
        self.res[depth].append(root.val)
        self.traverse(root.left, depth + 1)
        self.traverse(root.right, depth + 1)

dfs前序遍历模板。 用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。

def traverse(root):
    if root is None:
        return
    # 前序位置
    traverse(root.left)
    # 中序位置
    traverse(root.right)
    # 后序位置

101. 对称二叉树

class Solution:
    def isSymmetric(self, root: Optional[TreeNode]) -> bool:
        if root is None:
            return True #最初步的情况,root是空,直接结束。
        return self.check(root.left, root.right)
    def check(self, left, right):
        if left is None or right is None:
            return left == right   #这个很精妙,把left,right的三种情况包含了
        if left.val != right.val:
            return False 
        return self.check(left.right, right.left) and self.check(left.left, right.right)

if root1 is None or root2 is None: return root1 == root2

很精妙的代码,判断了root1和root2都是none返回true这种情形,和root1 或者root2有一个是None返回会false这两种情形

二叉树的直径是指任意两个节点之间路径的最长距离。这个路径不一定必须经过根节点,它可以通过树的任何部分。因此,二叉树的直径是以下三种情况中的最大值:

  1. 左子树的直径。
  2. 右子树的直径。
  3. 左子树的最大深度 + 右子树的最大深度。

为了计算二叉树的直径,可以使用递归的方法。在计算每个节点的左右子树最大深度的同时,也计算出通过该节点的路径长度。这样可以保证我们找到的最长路径,不论它是否经过根节点。 由于递归遍历了每个节点,所以不仅考虑了经过根节点的路径,还考虑了不经过根节点的所有路径。

class Solution:
    def __init__(self):
        self.max_diameter = 0 
    def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
        self.max_depth(root)
        return self.max_diameter 
    def max_depth(self, root):
        if root is None:
            return 0 
        left_max = self.max_depth(root.left)
        right_max = self.max_depth(root.right)#分解问题递归调用max_depth,分解到最后的叶子节点,
        
         #以简单二叉树进行举例好理解。
        self.max_diameter = max(self.max_diameter, left_max + right_max) 
        return 1 + max(left_max, right_max) #最大深度用来求直径用的.

543. 二叉树的直径 这是分解问题的思路,max_depth有返回值 分解问题也有后序位置

class Solution:
    def __init__(self):
        self.max_diameter = 0 
    def max_depth(self, root):
        if root is None:
            return 0 
        left_max = self.max_depth(root.left)
        right_max = self.max_depth(root.right)
        self.max_diameter = max(self.max_diameter, left_max + right_max) #在后续位置进行最大直径的更新
        return (1 + max(left_max, right_max))#返回最大深度  最大深度与单边路径和类似
    def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
        self.max_depth(root)  
        return self.max_diameter #直径等于左子树最大深度加上右子树最大深度分解问题

124. 二叉树中的最大路径和

在解决二叉树的最大路径和问题时,分解问题的关键在于理解路径可以从任意节点开始和结束,因此需要考虑每个节点及其左右子树的贡献。将问题分解为单边路径和是为了简化递归计算,并确保我们可以动态更新最大路径和

class Solution:
    def __init__(self):
        self.res = float('-inf') 
    
    def maxPathSum(self, root: Optional[TreeNode]) -> int:
        if root is None:
            return 0
        self.one_side_max(root)
        return self.res 
    def one_side_max(self, root) -> int:
        if root is None:
            return  0 
        left_max_sum = max(0, self.one_side_max(root.left)) 
        right_max_sum = max(0, self.one_side_max(root.right))
        path_max_sum = root.val + left_max_sum + right_max_sum #最大路径和
        self.res = max(self.res, path_max_sum)#在res处更新结果,总路径和
        return max(left_max_sum, right_max_sum) + root.val  #实现单边路径和

路径的定义

  • 路径可以从任意节点开始并在任意节点结束。
  • 路径必须连续,不能跳过节点。

单边路径和的定义

  • 对于一个节点,单边路径和是从该节点出发,通过其左子节点或右子节点的路径和,选择较大的一边。
  • 单边路径和的计算确保了递归过程的简单性,并且不会因为路径选择较小的一边而减小总路径和。 所以想到定义单边路径和这一个函数

标签:right,return,递归,max,self,二叉树,left,root,刷题
From: https://blog.csdn.net/m0_48938554/article/details/140927333

相关文章

  • NC 实现二叉树先序,中序和后序遍历
    系列文章目录文章目录系列文章目录前言前言前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。描述给定一棵二叉树,分别按照二叉树先序,中序和后序打印所有的节点。i......
  • LeetCode刷题-两数之和
    一、两数之和给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。示例1:输入:nums=......
  • 【网络安全】NISP一级二级备考指南,收藏复习不迷路!(附官方课程+刷题)_nisp二级需要准备多
    作为一名网安人,不考证怎么行呢?今天为大家整理了一份NISP备考指南,教大家如何在最短的时间拿证。收藏加关注,备考不迷路哦!那么,进入正题!NISP属于CISP的校园版,对拿学分、评奖评优、进入事业单位和安全企业都有好处。属于你不一定会用到,但必须有的证书。NISP一级考试共50......
  • Day21 二叉树Part8
    目录任务669.修剪二叉搜索树思路108.将有序数组转换为二叉搜索树思路538.把二叉搜索树转换为累加树思路心得体会任务669.修剪二叉搜索树给你二叉搜索树的根节点root,同时给定最小边界low和最大边界high。通过修剪二叉搜索树,使得所有节点的值在[low,high]中。修剪树不......
  • 手撕数据结构之二叉树
     1.树树的基本概念与结构树是⼀种⾮线性的数据结构,它是由n(n>=0)个有限结点组成⼀个具有层次关系的集合。把它叫做树是因为它看起来像⼀棵倒挂的树,也就是说它是根朝上,⽽叶朝下的。•有⼀个特殊的结点,称为根结点,根结点没有前驱结点。•除根结点外,其余结点被分成M(M>0)......
  • C语言day11(string函数族、递归函数、结构体、共用体、枚举)
    【1】string函数族1.strlen头文件:#include<string.h>格式:size_tstrlen(constchar*s);功能:计算字符串实际长度,不包括\0参数:s:目标字符串首地址返回值:字符串实际长度2.strcpy    头文件:#include<string.h>    格式:char*strcpy(char*dest,......
  • 高效刷题不再是梦
    不知道大家有没有遇到我去年刷题时遇到的难题困惑:手头资料某一专题的题目明明已经刷完了,却还是感觉自己这一专题知识点不够牢固仍需强化,买太多资料的话又担心贪多嚼不烂,去网上找题的话不仅费时费力,最后题目质量可能还不太行,导致刷题效率低下。如果你跟去年的我有一样的困扰的话......
  • 数据结构 顺序与链式二叉树的原理与实现(万字)
    目录一、树概念及结构树的概念树的相关概念树的表示二、二叉树概念及结构概念特殊的二叉树二叉树的性质二叉树的存储结构三、二叉树的顺序结构及实现二叉树的顺序结构堆的概念及结构堆的实现堆向下调整算法堆的创建建堆时间复杂度堆的插入堆的删除堆的代码实现Heap.hHeap.c堆的应......
  • Day20 二叉树Part7 二叉搜索树的增删查
    目录任务235.二叉搜索树的最近公共祖先思路701.二叉搜索树中的插入操作思路450.删除二叉搜索树中的节点思路心得体会任务235.二叉搜索树的最近公共祖先给定一个二叉搜索树,找到该树中两个指定节点的最近公共祖先。思路由于是二叉搜索树,所以可以利用其性质进行查找,即,只有......
  • c++递归
    这是我发的第一篇讲解类型的文章主要是报的班那边讲到了个很有趣的东西到时候会给些案例本期直接把花絮挂在最后面_____________________________________________________________________________c++里有两种函数一种是可以看成数据的(这种定义函数的类型有longlong,......