解法一:暴力法
根据题意,二叉树的直径,其实就是左右子树的最大深度之和,那么直接的想法是对每个节点计算左右子树的最大高度,得出每个节点的直径,从而得出最大的那个直径。
求最大深度的算法我们在这个题目中实现了:juejin.cn/post/747896…
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func diameterOfBinaryTree(root *TreeNode) int {
if root == nil{
return 0
}
var res int
traverse(root, &res)
return res
}
func traverse(root *TreeNode, maxDiameter *int) {
if root == nil {
return
}
// 求左右子树的最大深度
leftMax := maxDepth(root.Left)
rightMax := maxDepth(root.Right)
// 求每个节点的直径,并更新最大直径
curDiameter := leftMax+rightMax
*maxDiameter = max(*maxDiameter, curDiameter)
// 递归求左右子节点的直径
traverse(root.Left, maxDiameter)
traverse(root.Right, maxDiameter)
}
func maxDepth(root *TreeNode) int{
if root == nil{
return 0
}
maxLeft := maxDepth(root.Left)
maxRight := maxDepth(root.Right)
return max(maxLeft, maxRight) + 1
}
func max(a, b int) int{
if a > b {
return a
}
return b
}
这个解法是正确的,但是运行时间很长,原因也很明显,traverse 遍历每个节点的时候还会调用递归函数 maxDepth,而 maxDepth 是要遍历子树的所有节点的,所以最坏时间复杂度是 O(N^2)。
这是因为前序位置无法获取子树信息,所以只能让每个节点调用 maxDepth 函数去算子树的深度。
那如何优化?我们应该把计算「直径」的逻辑放在后序位置,准确说应该是放在 maxDepth 的后序位置,因为 maxDepth 的后序位置是知道左右子树的最大深度的。
解法二:优化后的后序遍历
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func diameterOfBinaryTree(root *TreeNode) int {
if root == nil{
return 0
}
var res int
_ = maxDepth(root, &res)
return res
}
func maxDepth(root *TreeNode, maxDiameter *int) int{
if root == nil{
return 0
}
maxLeft := maxDepth(root.Left, maxDiameter)
maxRight := maxDepth(root.Right, maxDiameter)
// 后续位置,已知节点左右子树最大深度,顺便更新最大直径
curDiameter := maxLeft+maxRight
*maxDiameter = max(*maxDiameter, curDiameter)
return max(maxLeft, maxRight) + 1
}
func max(a, b int) int{
if a > b {
return a
}
return b
}