题目
leetcode题目:(链接https://leetcode-cn.com/problems/diameter-of-binary-tree)。
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。
示例 :
给定二叉树
1
/ \
2 3
/ \
4 5
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
注意:两结点之间的路径长度是以它们之间边的数目表示。
基本思路
每一条路径都可以看做是某节点的左右侧最大深度的和。例如在上面的示例中,[4,2,1,3]这条路径可以看作是结点1的左侧最大深度(2)和右侧最大深度(1)的和(2+1=3)。所以我们可以采用递归的思想,从根结点开始遍历整棵树,计算每个结点的左右侧最大深度的和,该和的最大值即为所求。
具体代码
一开始我保存了所有路径的长度,最后取里面的最大值。并且花费了精力去处理叶子结点,虽然思路对了,但是造成了时间和空间上的浪费。
第一版代码:
//Java
class Solution {
ArrayList<Integer> result = new ArrayList<Integer>();
public int diameterOfBinaryTree(TreeNode root) {
if(root == null) {
return 0;
}
result.clear(); //leetcode中全局变量必须每次重新初始化
TreeNode node = root;
result.add(getDistance(node));
return Collections.max(result);
}
private int getDistance(TreeNode node) {
int maxDis = 0; //记录当前结点与最深层之间的距离
if(node.left != null && node.right != null) {
int l = getDistance(node.left);
int r = getDistance(node.right);
int n = l + r + 2; //记录路径长度,+2是因为当左右均不为空时,将左右侧连接会多长度会多2
maxDis = Math.max(l, r) + 1;
result.add(n);
} else if(node.left != null) {
int n = getDistance(node.left) + 1;
maxDis = n;
} else if(node.right != null){
int n = getDistance(node.right) + 1;
maxDis = n;
}
return maxDis;
}
}
经过后续优化,发现没有必要存储所有的路径长度,因为他们并不参与计算,仅仅需要其中的最大值。而且只要将空结点的判断放入getDistance函数中,就可以省掉对左右的判断,节约时间和空间。
最终版代码:
//Java
class Solution {
int result= 0;
public int diameterOfBinaryTree(TreeNode root) {
getDistance(root);
return result;
}
private int getDistance(TreeNode node) {
if(node == null) {
return 0;
}
int l = getDistance(node.left);
int r = getDistance(node.right);
result= Math.max(result, l + r); //这里不再加2是因为每次返回值已经加了1,不再具体区分是否有孩子结点
int maxDis = Math.max(l, r) + 1;
return maxDis;
}
}
时间复杂度:仅遍历了一遍二叉树,时间复杂度为
O
(
n
)
O(n)
O(n),n为结点数。
空间复杂度:该递归运算在树的每一层都需要分配常数个空间用于计算,所以空间复杂度取决于树的高度,空间复杂度为
O
(
h
)
O(h)
O(h),h为树高。