一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
前言:
每天一道算法题目,死磕算法
题目
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。
示例 : 给定二叉树
1
/ \
2 3
/ \
4 5
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
分析
Q:什么是二叉树直径?
A:所谓二叉树直接就是树中两片叶子之间最长路径上的节点数。
上图红色数字即为每个节点为顶点的路径长度,所有节点的路径长度的最大值即为二叉树的最大路径长度
一棵二叉树的直径长度,其实可以将其看为左右子树的最大深度之和。
如果真是这样的话,那么题目太简单了,可题目中有一个大坑
这条路径可能穿过也可能不穿过根结点。
意思就是有可能根节点的左右子树的直径不是最大的
就像上面这种情况一样,根节点的树的直径不是最大的
所以我们的思路如下
- 定义一个变量,记录所有节点的直径
- 遍历二叉树,计算所有结点的直径
- 通过Math.max得到最大的直径
首先我们复习一下,深度遍历获取树高度的模板
const dfs = function(root){
// 递归结束条件
if(!root){
return 0;
}
let left = dfs(root.left);
let right = dfs(root.right);
// 逆想思维求高度
return Math.max(left,right)+1;
}
所以我们的题解如下
题解
var diameterOfBinaryTree = function(root) {
// 返回的结果
let result = 0;
const dfs = function(root){
// 递归结束条件
if(!root){
return 0;
}
let left = dfs(root.left);
let right = dfs(root.right);
// left+right就是当前节点的直径
// result是遍历的以前节点的最大值
result = Math.max(result,left+right);
// 逆想思维求高度
return Math.max(left,right)+1;
}
// 进行深度优先遍历
dfs(root)
return result;
};
- 时间复杂度:O(n),其中n为二叉树的节点个数。因为每个节点都会处理一次
- 空间复杂度:O(Height),其中 Height 为二叉树的高度。由于递归函数在递归过程中需要为每一层递归函数分配栈空间,所以这里需要额外的空间且该空间取决于递归的深度,而递归的深度显然为二叉树的高度,并且每次递归调用的函数里又只用了常数个变量,所以所需空间复杂度为 O(Height) 。