【LeetCode】二叉树最大路径和(dfs)

二叉树最大路径和

题目链接:https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/

分析:

这个题目是求二叉树的最大路径和,要点有两个:

  • 最大不能走回头路:从根节点延伸的路径,你不能走了左子树又掉过头来走右子树
  • 最大路径不一定要经过根节点

思路:

对每个非叶子节点,其实都面临这样一个问题:求解从此节点开始的最大路径和,所以求解从根节点开始的最大路径和其实可以分解成很多的子问题,这些子问题在根本上其实都是一个问题,有个通用的解法,所以我们可以采取递归的方式,即dfs深度搜索

针对每个节点,其最大收益分三种情况:

  • 只走此节点,不走其左右孩子 ,收益:root.val
  • 走此节点,并走入其左子树,收益:root.val+dfs(root.left)
  • 走此节点,并走入其右子树,收益:root.val+dfs(root.right)

每个节点的收益仅有上面三种情况,对每个节点,取这三种情况的最大值即可:

root.val+max(0, dfs(root.left), dfs(root.right))

这也是当前子树能够提供给外部的最大路径和,即左右孩子只能选择一个走

一个子树内部最大的路径和:左子树的最大路径和+右子树的最大路径和+根节点值,即dfs(root.left)+root.val+dfs(root.right)

上述两种情况,分别是子树提供给外部(其父节点)的最大路径和,子树自身内部的最大路径和

对于每个子问题,我们递归时都需要返回子树提供给外部的最大路径和

而对于子树自身内部最大的路径和,每次都有比较记录一下,取最大值

var result int // 记录最大路径和

// dfs 求从root开始的最大路径和
func dfs(root *TreeNode) int{

	// 遍历到nil节点,收益为0
	if root==nil{
		return 0
	}

	left:=dfs(root.Left) // 左子树内部提供的最大路径和
	right:=dfs(root.Right) // 右子树内部提供的最大路径和

	innerMaxSum:=left+root.Val+right // 当前子树内部的最大路径和
	result=max(result,innerMaxSum)  // 挑战一下最大路径

	outputMaxSum:=root.Val+max(0,max(left,right)) // 当前子树对外提供的最大路径和

	// 如果子树对外提供的最大路径和为负数,则返回0,因为负数子树对最大路径和毫无贡献
	if outputMaxSum<0{
		return 0
	}
	return outputMaxSum // 返回当前子树对外提供的最大路径和,这是每个子问题的解

}

func max(a,b int) int{
	if a>b{
		return a
	}
	return b
}
func maxPathSum(root *TreeNode) int {
	result=math.MinInt64

	dfs(root)

	return  result
}

耗时分析:

时间复杂度:O(N),每个节点都需要遍历

空间复杂度:O(H),也就是递归的深度,跟树的形状有关

总结:

  • 学会把大问题拆解成很多子问题,每个子问题其实都是相似的,子问题有解决方案了,综合一下大问题也就解决了
  • 通过求出每个子树对外提供的最大路径和,从递归树底部向上,不断求出每个子树内部的最大路径和(记录最大值),后者是求解的目标,后者的求解需要前者
  • 每个子树内部的最大路径和,都挑战一下最大路径和,这样递归结束时,最大路径和也就出来了
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值