【笔记】前缀和难题?二叉树路径问题题目1

二叉树的所有路径

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

        属于自顶向下问题

        解题思路:1.对于一个节点先将他的值放到路径字符串中

                        2.判断该节点是不是叶子节点:是叶子节点该路径到此为止,非叶子结点继续遍历

                        3.根据输出形式,答案输出为列表形式,每一个路径是字符串形式

def binaryTreePaths(self, root):
        """
        :type root: TreeNode
        :rtype: List[str]
        """
        def allPath(root,path):
            if root:
                path+=str(root.val)
                if not root.left and not root.right:
                      #叶子节点到此为止
                      paths.append(path)
                else:   #非叶子节点继续该路径探索
                    path+='->'
                    allPath(root.left,path)
                    allPath(root.right,path)
        paths=[]
        allPath(root,'')
        return paths

    

路径总和

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

        解题思路:1.确定返回一个列表,列表元素也是列表且是所有值组成的

                           2.该节点的值加入列表,减少目标和

                           3.判断是否退出循环:若退出则满足题意,将该元素添加到答案列表,若不是则继续遍历左右子树

class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
        ret = list()
        path = list()#列表内元素
        
        def dfs(root: TreeNode, targetSum: int):
            if not root:#空树
                return
            path.append(root.val)#把该节点的值加入
            targetSum -= root.val#减少目标和
            if not root.left and not root.right and targetSum == 0:#到达叶节点且目标和满足
                ret.append(path[:])#该条路径作为元素添加到答案列表
            dfs(root.left, targetSum)
            dfs(root.right, targetSum)
            path.pop()
        
        dfs(root, targetSum)
        return ret

路径总和

        

        给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目

        路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

        解题思路1:遍历。1.对于一个节点先判断到他为止是不是等于路径和,是路径和就加一

                                        2.遍历左右子树,此时路径和要减去父节点的值

                     

class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> int:
        def rootSum(root, targetSum):#参数是当前节点和总和
            if root is None:
                return 0

            ret = 0        #初始路径数目为0
            if root.val == targetSum:#节点值等于总和,符合路径数目加一
                ret += 1

            ret += rootSum(root.left, targetSum - root.val)#计算左子树
            ret += rootSum(root.right, targetSum - root.val)#计算右子树
            return ret
        
        if root is None:
            return 0
            
        ret = rootSum(root, targetSum)
        ret += self.pathSum(root.left, targetSum)
        ret += self.pathSum(root.right, targetSum)
        return ret

                解题思路2:前缀和,两节点的路径等于前缀和之差(自上往下)

                                        1.遍历树计算出各个节点的前缀和

                                         2.从根节点到p节点的距离是差值,那么从p1到p节点的距离一定是总和

class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> int:
        prefix = collections.defaultdict(int)#用来计数的字典
        prefix[0] = 1

        def dfs(root, curr):#输入前缀和
            if not root:
                return 0
            
            ret = 0
            curr += root.val#记录当前前缀和
            ret += prefix[curr - targetSum]#记录当前前缀和与总和差对应的次数
            prefix[curr] += 1    #该前缀和出现的次数
            ret += dfs(root.left, curr)
            ret += dfs(root.right, curr)
            prefix[curr] -= 1    #?

            return ret

        return dfs(root, 0)

从叶节点开始的最小字符串

        给定一颗根结点为 root 的二叉树,树中的每一个结点都有一个 [0, 25] 范围内的值,分别代表字母 'a' 到 'z'。返回 按字典序最小 的字符串,该字符串从这棵树的一个叶结点开始,到根结点结束。注:字符串中任何较短的前缀在 字典序上 都是 较小 的:例如,在字典序上 "ab" 比 "aba" 要小。叶结点是指没有子结点的结点。 

        解题思路:创建所有可能的字符串,然后进行比较。自顶而下寻找,然后将字符串逆序

class Solution(object):
    def smallestFromLeaf(self, root):
        self.ans = "~"

        def dfs(node, A):
            if node:  #节点存在,将该节点值所代表的字母存入序列A  
                A.append(chr(node.val + ord('a')))
                if not node.left and not node.right:    #是叶节点结束寻找,开始比较
                    self.ans = min(self.ans, "".join(reversed(A)))#将序列逆转,每次都与上一个比较取最小值

                dfs(node.left, A)
                dfs(node.right, A)
                A.pop()

        dfs(root, [])
        return self.ans

二叉树中最大路径和

        

        路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

                路径和 是路径中各节点值的总和

        给你一个二叉树的根节点 root ,返回其 最大路径和 

        解题思路:非自顶向下。对路径上的节点node来说有三种情况:

                                1.nodeleft+node有最大路径和

                                2.noderight+node有最大路径和

                                3.noderight+nodeleft+node有最大路径和

                                要注意第三种情况当出现负数路径直接舍弃

def MaxPath():
    
    def dfs(node):
        if !node:
             return 0;#空树

        
         left_max  = max(0, dfs(node->left));#寻找左子树的最长路径,是负数取0
         right_max = max(0, dfs(node->right));#寻找右子树最长路径,是负数取0
        
        
         lnr_sum = left_max + node->val + right_max;#对应情况三
        
        max_sum = max(max_sum, lnr_sum);#计算三种情况中最大路径和

        
        ret = node->val + max(left_max, right_max);#向上一个节点返回该节点单边最大路径和
        return ret;
    return max_sum

最长同值路径

        

        给定一个二叉树的 root ,返回 最长的路径的长度 ,这个路径中的 每个节点具有相同值 。 这条路径可以经过也可以不经过根节点

        两个节点之间的路径长度 由它们之间的边数表示。

        解题思路:

                

class Solution:
    def longestUnivaluePath(self, root: Optional[TreeNode]) -> int:
        maxans = 0  
        def dfs(node: Optional[TreeNode]) -> int:
            if node is None:#空树
                return 0
            left = dfs(node.left)#计算左子树的最长路径
            right = dfs(node.right)#计算右子树的最长路径
            left1 = left + 1 if node.left and node.left.val == node.val else 0
            #只有当子树存在并且同值时路径长度加一,否则为0
            right1 = right + 1 if node.right and node.right.val == node.val else 0
            nonlocal maxans     #nonlocal修改嵌套函数中上一级的局部变量
             maxans= max(maxans, left1 + right1)
            return max(left1, right1)    #将当前左右子树最长路径返回给父节点
        dfs(root)
        return ans

二叉树直径

        给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。

        解题思路:

                一条路径的长度为该路径经过的节点数减一,所以求直径(即求路径长度的最大值)等效于求路径经过节点数的最大值减一。任意一个node所在的路径是其左子树路径加上右子树路径

class Solution:
    def diameterOfBinaryTree(self, root: TreeNode) -> int:
        self.ans = 1
        def depth(node):
           
            if not node:     # 访问到空节点了,返回0
                return 0
            
            L = depth(node.left)    # 左儿子为根的子树的深度
           
            R = depth(node.right)     # 右儿子为根的子树的深度
           
            self.ans = max(self.ans, L + R + 1)    #节点数是左右深度加上自身
            
            return max(L, R) + 1    # 返回该节点为根的子树的深度

        depth(root)
        return self.ans - 1    #路径长度就是节点数-1
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值