力扣652题、124题(二叉树,递归)

652.寻找重复的子树

1.基本思想:

  将树中每个节点开始的子树序列化,保存后,判断比较是否存在重复的子树

2.具体实现:

后序遍历

(1)设置空列表为放结果的列表

(2)一个新的函数

         递归序列化二叉树

(3)递归后进行其他操作就是后序遍历

         用count来计数

(4)对应的字符串个数如果等于2,说明有重复的,将字符串写入结果列表中

上述两个过程是在一个函数里,也就是序列化一点计数一点,序列化完了也就计数完了

要先序列化,序列化用的是递归,先递归所以就是后序遍历

先序遍历 

避免使用这种方法,因为他是一个递归函数里调用了其他递归函数,使用后序遍历是在进行优化

(1)用一个函数把整个二叉树都序列化,返回序列化的二叉树

(2)在另一个函数里计数,

         一个根节点出现两次的话,再重复遍历一遍子树的值才能确定当前节点的值

 

为什么要使用后序遍历?

后序遍历确定了子树相同后马上就可以把这个子树写进结果列表。

前序遍历是判断完是相同子树,再把这个子树写进结果的时候还需要遍历。

 

3.代码:

两个后序遍历

 

 

 

一个先序遍历

 

 

124、二叉树最大最大路径和

基本思想:

使用后序遍历,因为路径和需要从叶子节点开始积累

后序遍历,会先走到叶子节点处再往上走

具体实现:

1、如果左右子树是负数就要舍弃

max(0,左右子树),如果左右子树是负数就会选择0

2、递归往上返回的值,不是最大路径

而是比较过大小的左右子树,较大的那个和节点的和

return  node.val + Math.max(leftGain, rightGain)

意思就是左右子树选一个大的向上返回

3、设一个变量存储最大路径,比较大小后,不断更新成最大的

priceNewpath = node.val + leftGain + rightGain

maxSum = Math.max(maxSum, priceNewpath)

4、初始化maxSum不能为0,应该为负无穷,因为有可能返回的最大值是一个负值

举例:

自底向上走,先从最底下的子树看最大路径和是多少。

      -10
     /   \
   -1     -5
         /   \
       -2    -3

(1)会先找到叶子节点-1,站在-1往下看:它底下没有节点,所以通过下面两句得到当前子树的最大路径是-1;
priceNewpath = node.val + leftGain + rightGain=-1+0+0=-1
self.maxSum = max(self.maxSum, priceNewpath)=max(-2147483648,-1)=-1

(2)然后找到-2,站在-2往下看:它底下没有节点,所以当前子树的最大路径是-2;接着与之前的最大路径和比较:
priceNewpath = node.val + leftGain + rightGain=-2+0+0=-2
self.maxSum = max(self.maxSum, priceNewpath)=max(-1,-2)=-1
好吧,还不如我就在-1这个路径原地踏步。-3也是同理,还是不如就呆在-1

(3)往上到了节点-5,站在-5往下看:它左子树的路径和是-2,比0还小,不走它就是了,因为把-1加上还不如我-5自己。
它的右子树的路径和是-3,也比0小,那我也不走它。这也就是下面这两行代码的意思。
leftGain = max(maxGain(node.left), 0)
rightGain = max(maxGain(node.right), 0)

所以此时计算当前子树的路径和就是:
priceNewpath = node.val + leftGain + rightGain=-5+0+0=-2
然后去跟之前的最大路径比一下:
self.maxSum = max(self.maxSum, priceNewpath)=max(-1,-5)=-1
(4)在往上一样的道理,每看一棵子树它都会算一下子树内的最大路径和并把结果返回给上一层。最终结果最大路径和就是 -1 。

代码:

class Solution:
    def __init__(self):
        self.maxSum = float("-inf")

    def maxPathSum(self, root: TreeNode) -> int:
        def maxGain(node):
            if not node:
                return 0

            # 递归计算左右子节点的最大贡献值
            # 只有在最大贡献值大于 0 时,才会选取对应子节点
            leftGain = max(maxGain(node.left), 0)
            rightGain = max(maxGain(node.right), 0)
            
            # 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
            priceNewpath = node.val + leftGain + rightGain
            
            # 更新答案
            self.maxSum = max(self.maxSum, priceNewpath)
        
            # 返回节点的最大贡献值
            return node.val + max(leftGain, rightGain)
   
        maxGain(root)
        return self.maxSum

 

posted @ 2020-12-03 17:02  最近饭吃的很多  阅读(123)  评论(0编辑  收藏  举报