首页 > 其他分享 >Day15 二叉树Part2 初见回溯(二叉树相关)

Day15 二叉树Part2 初见回溯(二叉树相关)

时间:2024-07-31 13:51:12浏览次数:16  
标签:node self Day15 Part2 二叉树 path root 节点 left

任务

110.平衡二叉树

给定一个二叉树,判断它是否是 平衡二叉树

思路

典型的树形DP,每个节点向它的左右孩子收集信息,然后利用收集到的信息判断当前节点,最后再将信息传给上层。对于本题,每个节点要判断以自己为根的树是否是平衡二叉树,需要判断3个条件:

  1. 自己的左子树是否平衡
  2. 自己的右子树是否平衡
  3. 自己的左右高度是否相差<=1
    只有满足这三个条件,以当前节点为根的二叉树才平衡,返回给上层。
class Solution:
    def isBalanced(self, root: Optional[TreeNode]) -> bool:
        height,balanced = self.isNodeBalanced(root)
        return balanced

    def isNodeBalanced(self,node):
        if not node: return 0,True
        
        leftHeight,isLeftB = self.isNodeBalanced(node.left)
        rightHeight,isRighttB = self.isNodeBalanced(node.right)
        
        curNodeHeight =  max(leftHeight,rightHeight)+1
        res = abs(leftHeight - rightHeight)  <= 1 and isLeftB and isRighttB
        return curNodeHeight,res

257. 二叉树的所有路径

给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。

思路

采用遍历的思路:

  1. 对于任意节点,每次首次遍历到节点就将其加入到path中。
  2. 对于任意节点,递归遍历其左右节点
  3. 遇到叶子节点后,将之前收集到的路径加入到paths中。
  4. 从任意节点退出后,需要回溯path。
class Solution:
    def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
        if not root: return []
        paths =[]
        path = []
        self.dfs(path,root,paths)
        return paths
#解法1:当前节点退出时,回溯处理,元素出栈
    def dfs(self,path,node,paths):
        if not node: return            
        path.append(node.val)
        if (not node.left and not node.right):
            paths.append('->'.join(map(str,path)))
        else:
            self.dfs(path,node.left,paths)
            self.dfs(path,node.right,paths)
        
        path.pop()

代码随想录与我的思路有些许不同,他的思路是任意节点的子节点返回时回溯,特别的,对于叶子节点,因为左右都为空,所以直接返回。细微之处需要细细体会,代码如下:

#解法2: 当前节点的左右孩子返回时,回溯处理,元素出栈
    def dfs(self,path,node,paths):
                   
        path.append(node.val)  #当前节点加入到路径
        if (not node.left and not node.right): # 作为叶子节点的处理
            paths.append('->'.join(map(str,path)))
            return
        else:
            if node.left:
                self.dfs(path,node.left,paths)
                path.pop() 
            if node.right:    
                self.dfs(path,node.right,paths)
                path.pop() #处理完后当前节点从路径中移除

此外,还可以用隐形回溯,即使用当前层递归函数的局部变量记录路径,从下一层返回时就可以不用显示的调用pop,局部变量就会从之前的函数栈中弹出而保证正确性了。

def dfs(self,node,path,paths):
        if not node: return 
        new_path = path[:] + [node.val]
        if not node.left and not node.right:
            paathStr = '->'.join(map(str,new_path))
            paths.append(paathStr)
        
        self.dfs(node.left,new_path,paths)
        self.dfs(node.right,new_path,paths)

404. 左叶子之和

给定二叉树的根节点 root ,返回所有左叶子之和。

思路

由于int类型为不可变类型,所以用成员变量统计sum,也是遍历的思路,递归遍历左右,到达左叶子时处理信息(修改sum)。

class Solution:
    def __init__(self):
        self.sum = 0
    def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
        self.dfs(root)
        return self.sum
    def dfs(self,node):
        if not node: return 0
        self.dfs(node.left)
        self.dfs(node.right)
        if node.left:
            if not node.left.left and not node.left.right: # 左叶子
                self.sum += node.left.val

个人觉得代码随想录的方法在理解上比较难,不是很直观,其代码如下:

class Solution:
    def sumOfLeftLeaves(self, root):
        if root is None:
            return 0
        if root.left is None and root.right is None:
            return 0
        
        leftValue = self.sumOfLeftLeaves(root.left)  # 左
        if root.left and not root.left.left and not root.left.right:  # 左子树是左叶子的情况
            leftValue = root.left.val
            
        rightValue = self.sumOfLeftLeaves(root.right)  # 右

        sum_val = leftValue + rightValue  # 中
        return sum_val

513.找树左下角的值

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。

思路

遍历思路,每次遇到叶子节点,判断其是否是最底层的。
实际编码中,使用depth记录当前节点的深度,使用maxDepth记录最大深度。
由于depth>self.maxDepth,所以每次最底层碰到的第一个节点就会被记录,而同层其他的节点的深度等于该节点,所以不会被更新。

class Solution:
    def __init__(self):
        self.maxDepth = float('-inf')
        self.res = 0
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        self.dfs(root,0)
        return self.res
    def dfs(self,node,depth):
        if not node: return 
        if not node.left and  not node.right: # 叶子节点
            if depth > self.maxDepth:
                self.maxDepth = depth
                self.res = node.val
        
        self.dfs(node.left,depth+1)
        self.dfs(node.right,depth+1)

心得体会

更新了对二叉树章节中递归的思考。

  1. 上节课中树形DP的思路,一般只考虑单层递归逻辑和递归基,如我这个节点和我左右孩子要做什么(局部),我左右子树要做什么(递归)
  2. 本节的二叉树的所有路径,左叶子之和以及找树左下角的值都是考虑遍历的思路,也就是在思考上,需要去判断我们在遍历过程中需要收集的信息,放入全局变量,然后再考虑单层逻辑,特殊节点逻辑等。特别的,单层逻辑中,需要考虑相对全局变量的回溯,或者利用局部变量隐形回溯。(注:这里的全局变量指的是比当前局部作用域更大的变量,如可变类型的参数,类的成员等)单层逻辑中一般考虑该节点怎么收集,离开该节点时怎么处理。

标签:node,self,Day15,Part2,二叉树,path,root,节点,left
From: https://www.cnblogs.com/haohaoscnblogs/p/18334453

相关文章

  • DAY12 二叉树part02
     今日任务二叉树的对称性翻转二叉树二叉树的最大/小深度(递归法)226.翻转二叉树(优先掌握递归)题目链接/文章讲解/视频讲解:https://programmercarl.com/0226.%E7%BF%BB%E8%BD%AC%E4%BA%8C%E5%8F%89%E6%A0%91.html1/**2*Definitionforabinarytreenode.3*s......
  • 代码随想录day14 || 226 翻转二叉树,101 对称二叉树, 104 二叉树的最大深度, 111 二叉树
    226翻转二叉树funcinvertTree(root*TreeNode)*TreeNode{ //思考,广度优先遍历,对于每一层,翻转其左右子节点 ifroot==nil{ returnnil } queue:=list.New() queue.PushBack(root) size:=1//存储每一层的节点个数 forqueue.Len()>0{ varcountint ......
  • Day14 二叉树Part2 递归的应用(二叉树相关)
    任务226.翻转二叉树给你一棵二叉树的根节点root,翻转这棵二叉树,并返回其根节点。思路逻辑上,我们知道用递归遍历一棵树,一定会遍历每个节点。因此在遍历的过程中处理即可。考虑递归基,即当节点为空时直接返回。考虑单层递归,为了反转二叉树,如何处理当前节点呢?即如何反转以当......
  • 算法笔记|Day11二叉树
    算法笔记|Day11二叉树☆☆☆☆☆leetcode144.二叉树的前序遍历题目分析代码☆☆☆☆☆leetcode94.二叉树的中序遍历题目分析代码☆☆☆☆☆leetcode145.二叉树的后序遍历题目分析代码☆☆☆☆☆leetcode102.二叉树的层序遍历题目分析代码☆☆☆☆☆leetcode107.......
  • LeetCode - #107 二叉树的层序遍历 II
    文章目录前言1.描述2.示例3.答案关于我们前言我们社区陆续会将顾毅(Netflix增长黑客,《iOS面试之道》作者,ACE职业健身教练。)的Swift算法题题解整理为文字版以方便大家学习与阅读。LeetCode算法到目前我们已经更新到105期,我们会保持更新时间和进度(周一、......
  • DAY13 二叉树part01
     今日任务 二叉树的递归遍历(前中后)二叉树的迭代遍历(前中后)二叉树的统一迭代遍历二叉树的层序遍历(共十道题目)完成情况递归已掌握,代码略迭代前中手写一编,后和统一未学习层序遍历题目如下102.二叉树的层序遍历1/**2*Definitionforabinarytreenode.3*s......
  • LeetCode LCR 124.推理二叉树(哈希表 + 建树)
    某二叉树的先序遍历结果记录于整数数组 preorder,它的中序遍历结果记录于整数数组 inorder。请根据 preorder 和 inorder 的提示构造出这棵二叉树并返回其根节点。注意:preorder 和 inorder 中均不含重复数字。示例1:输入:preorder=[3,9,20,15,7],inorder=......
  • Day13 二叉树Part1 遍历
    递归遍历要理解递归,可以借助二叉树的递归遍历来理解。下面是二叉树递归遍历,以这个为例,来阐述下递归的原理。#Definitionforabinarytreenode.#classTreeNode:#def__init__(self,val=0,left=None,right=None):#self.val=val#self.left=......
  • LeetCode654. 最大二叉树
    题目链接:https://leetcode.cn/problems/maximum-binary-tree/description/题目叙述给定一个不重复的整数数组nums。最大二叉树可以用下面的算法从nums递归地构建:创建一个根节点,其值为nums中的最大值。递归地在最大值左边的子数组前缀上构建左子树。递归地在最大......
  • 数据结构-二叉树、堆、图
    一、线索二叉树规律:在有n个节点的链式二叉树中必定存在n+1个空指针链式二叉树中有很多的空指针,可以让这些空指针指向前一个节点\后一个节点,从而在有序遍历(中序遍历)二叉树时,不需要使用递归而通过循环即可以完成,并且效率要比递归快得多一定是搜索二叉树线索二叉树的结构typ......