首页 > 其他分享 >Day16 二叉树Part4 常规递归和遍历法的综合应用(二叉树相关)

Day16 二叉树Part4 常规递归和遍历法的综合应用(二叉树相关)

时间:2024-08-01 11:30:45浏览次数:9  
标签:node right return self Day16 Part4 二叉树 root left

目录

任务

112. 路径总和

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。叶子节点 是指没有子节点的节点。

思路

这道题非常的有典型性,首先,它和路径有关,根据昨天所学习的,路径相关的问题可以按照先序遍历树,然后添加节点进路径中,适当时需要回溯,即利用了遍历法。另外,此题的题意可以转化为:已经累计了sum,剩余的值相加是否可以达到target,左子树中是否有这样的路径,右子树中是否有这样的路径,这个思路又用了传统递归的逻辑。即一道题用了之前提到的两种思路。

# 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.sum = 0
    def hasPathSum(self, root, targetSum):
        """
        :type root: TreeNode
        :type targetSum: int
        :rtype: bool
        """
        return self.dfs(root,targetSum)
    def dfs(self,node,target):
        if not node:return False
        
        self.sum += node.val #第一次访问节点时做路径和累加
        if not node.left and not node.right:    # 到叶子判断是否符合条件
            if self.sum == target:
                return True
            else: return False
        else:    # 对于普通节点,
            lres = False
            rres = False
            if node.left:
                lres =  self.dfs(node.left,target)
                self.sum -= node.left.val
            if node.right:
                rres =  self.dfs(node.right,target)
                self.sum -= node.left.val
            return lres or rres
####else中的代码可以优化成下面这样
            # if node.left:
            #     if self.dfs(node.left,target): return True
            #     self.sum -= node.left.val
            # if node.right:
            #     if self.dfs(node.right,target): return True
            #     self.sum -= node.right.val
            # return False

或者将sum作为参数传递,由于int是不可变类型,所以改为参数后,相当于局部变量,就不需要显式回溯了。

class Solution(object):
    def hasPathSum(self, root, targetSum):
        """
        :type root: TreeNode
        :type targetSum: int
        :rtype: bool
        """
        return self.dfs(root,targetSum,0)
    def dfs(self,node,target,sum):
        if not node:return False
        
        sum += node.val #第一次访问节点时做路径和累加
        if not node.left and not node.right:    # 到叶子判断是否符合条件
            if sum == target:
                return True
            else: return False
        else:    # 对于普通节点,找了了就返回True,都没找到才返回False
            if node.left:
                if self.dfs(node.left,target,sum): return True
            if node.right:
                if self.dfs(node.right,target,sum): return True
            return False

实际上,上述代码还可以优化,即不需要sum变量,只需要Target变量在到达叶子时为0即可。

class Solution(object):
    def hasPathSum(self, root, targetSum):
        """
        :type root: TreeNode
        :type targetSum: int
        :rtype: bool
        """
        return self.dfs(root,targetSum)
    def dfs(self,node,target):
        if not node:return False
        
        target -= node.val #第一次访问节点时用目标值减去节点值
        if not node.left and not node.right:    # 到叶子判断是否符合条件
            if 0 == target:
                return True
            else: return False
        else:    # 对于普通节点,找了了就返回
            if node.left:
                if self.dfs(node.left,target): return True
            if node.right:
                if self.dfs(node.right,target): return True
            return False

113. 路径总和 II

给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。

思路

这道题看起来比上题难,要收集所有路径,上题只要找到一个返回True就行,实际上,该题的思路比上题简单的多。
由于是收集路径,我们只要遍历过程中,append列表,到叶子节点时,收集符合条件的路径就行。另外,由于path是参数和可变类型变量,因此归的时候需要回溯。并且,由于path可变类型和参数,所以加入到paths中时需要用其副本,避免被后续path的修改影响。

class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        path = []
        paths = []
        self.dfs(root,targetSum,0,path,paths)
        return paths        
    def dfs(self,node,target,sum,path,paths):
        if not node: return []
        
        sum += node.val
        path.append(node.val)
        if not node.left and not node.right:  #到达叶子节点,收集路径
            if sum == target:
                paths.append(path[:])
        
        # 普通节点继续向左右递归遍历
        if node.left:
            self.dfs(node.left,target,sum,path,paths)
        if node.right:
            self.dfs(node.right,target,sum,path,paths)
        
        path.pop() # 回溯

用局部变量隐式回溯的方法

class Solution:
    def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
        path = []
        paths = []
        self.dfs(root,path,paths)
        return paths
    def dfs(self,node,path,paths):
        if not node: return 
        print(path)
        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)

106. 从中序与后序遍历序列构造二叉树

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。inorder 和 postorder 都由 不同 的值组成

思路

根据后序数组的最后一个数建立树根,找到其在中序数组中的位置,这个位置将中序数组分为了,左中右,根据区间长度(左,右),将后序数组也分为了左右中,接着,递归的建立树根的左右子树,返回即可,这里要注意的是区间正确。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
        if len(postorder) == 0:
            return None
    
        rootVal = postorder[-1] # 根据后序数组的最后一数创建一个节点,即为中间节点
        root = TreeNode(rootVal)
        
        
        index = 0
        while index < len(inorder):
            if inorder[index] == rootVal:
                break
            index+=1
        
        
        leftInOrder = inorder[:index]                          # 左闭右开区间
        rightInOrder = inorder[index+1:len(inorder)]
        
        leftPostOrder = postorder[:index]
        rightPostOrder = postorder[index:len(inorder)-1]
        
        root.left = self.buildTree(leftInOrder,leftPostOrder)
        root.right = self.buildTree(rightInOrder,rightPostOrder)
        return root

105. 从前序与中序遍历序列构造二叉树

思路

修改下区间的定义即可,与上题基本一致。

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
        if len(preorder) == 0:
            return None
    
    
        rootVal = preorder[0] # 根据前序数组的第一数创建一个节点,即为中间节点
        root = TreeNode(rootVal)
        print(rootVal)
        
        index = 0
        while index < len(inorder):
            if inorder[index] == rootVal:
                break
            index+=1
        
        
        leftInOrder = inorder[:index]                          # 左闭右开区间
        rightInOrder = inorder[index+1:len(inorder)]
        
        leftPreOrder = preorder[1:index+1]
        rightPreOrder = preorder[index+1:len(inorder)]
        
        root.left = self.buildTree(leftPreOrder,leftInOrder)
        root.right = self.buildTree(rightPreOrder,rightInOrder)
        return root

心得体会

今天的题目中,路经总和非常具有典型性,包含了之前学习的遍历和递归的两种思路.
路径总和II 练习了遍历的思路。
也给除了很多解法(局部变量(不可变类型参数,函数内局部变量),全局变量(成员变量,可变类型参数),隐式回溯,显示回溯),需要细细体会。

标签:node,right,return,self,Day16,Part4,二叉树,root,left
From: https://www.cnblogs.com/haohaoscnblogs/p/18336294

相关文章

  • 实训日记day16
    web服务安装与部署web基本概念和常识web服务为⽤户提供的⼀种在互联⽹上浏览信息的服务,Web服务是动态的、可交互的、跨平台的和图形化的。Web服务为⽤户提供各种互联⽹服务,这些服务包括信息浏览服务,以及各种交互式服务,包括聊天、购物、学习等等内容。......
  • Day15 二叉树Part2 初见回溯(二叉树相关)
    任务110.平衡二叉树给定一个二叉树,判断它是否是平衡二叉树思路典型的树形DP,每个节点向它的左右孩子收集信息,然后利用收集到的信息判断当前节点,最后再将信息传给上层。对于本题,每个节点要判断以自己为根的树是否是平衡二叉树,需要判断3个条件:自己的左子树是否平衡自己的右子......
  • 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=......