题目
给你一棵二叉树的根节点,返回该树的 直径 。
二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。
两节点之间路径的 长度 由它们之间边数表示。
示例 1:
输入:root = [1,2,3,4,5]
输出:3
解释:3 ,取路径 [4,2,1,3] 或 [5,2,1,3] 的长度。
示例 2:
输入:root = [1,2]
输出:1
提示:
树中节点数目在范围 [1, 104] 内
-100 <= Node.val <= 100
解题思路
二叉树基本上第一反应就是递归,求直径的思路就是:
- 左子树为空:“右子树根节点到叶子节点的路径长度”和“右子节点为根结点的二叉树直径”的最大值
- 右子树为空:“左子树根节点到叶子节点的路径长度”和“左子节点为根结点的二叉树直径”的最大值
- 左子树和右子树都不为空:“根节点到左子树叶子节点的距离+根节点到右子树叶子节点的距离”,“左子节点为根结点的二叉树直径”和“右子节点为根结点的二叉树直径”的最大值
而要求以某个节点到叶子节点的最大路径长度,实际上就是求该节点的左子树和右子树的最大深度。这又是一个递归问题。所以可以定义一个函数 longestPathFromNode
,它的参数是一个节点,返回该节点到叶子节点的最大路径长度。
1 | func longestPathFromNode(node *TreeNode) int { |
然后就可以编写函数 diameterOfBinaryTree
,它的参数是一个节点,返回该节点的直径。
1 | func diameterOfBinaryTree(root *TreeNode) int { |
其中 root.Left == root.Right
的判断是如果当前节点的左右子树都为空,则返回 0。
用测试数据验证一下:
1 | func arrayToBinaryTree(arr []interface{}) *TreeNode { |
能通过测试,输出结果为 8
。其实细想一下,每一个直径一定会有一个顶节点。所以可以遍历整个二叉树,以每一个节点为顶节点来计算直径。而每一个节点的直径都可以通过左右树的深度相加来求得。
遍历二叉树的方式有很多种,实现上一般是借助栈或者递归来实现。考虑上面编写的函数 longestPathFromNode
,其用于计算某个节点到叶子节点的最大路径长度。在递归的过程中,其实已经遍历了整棵树。我们可以在这个函数中,顺便计算出当前节点的直径。这样就不需要再遍历一次了。
1 | func diameterOfBinaryTree(root *TreeNode) (maxDiameter int) { |
这样就可以在一次遍历中计算出整棵树的直径了。