提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
想要求解一个二叉树的深度和直径,首先需要明确什么是二叉树的深度和直径。
一、二叉数的深度和直径是什么?
二叉树的深度:从根节点到最远叶节点的最长路径上的节点数量。
二叉树的直径:二叉树中任意两个节点之间的最长路径长度,这里的路径长度是指经过的边的数量。
如下是一个简单的二叉树:
5
/ \
3 8
/ / \
2 7 9
/ /
1 6
根据上述概念我们可以很容易的找到:
该二叉树的深度为4(5-3-2-1或者5-8-7-6)
该二叉树的直径为6(1-2-3-5-8-7-6)
当二叉树的节点较少,结构比较简单的时候,我们可以一眼发现最长的那条路径,但如果希望通过代码来实现这个需求,我们应该怎么办呢?
现已知:我们的目的是找到最长的“路径”,那么最后我们一定要返回一个整数(用来表示这个树的深度/直径)。
因此我们可以定义一个函数用来计算深度/直径(传入树的节点参数,输出以该节点为根节点时的深度/直径)。
二、求二叉树的深度
定义一个函数 maxDepth,传入树的根节点,返回树的深度。
int maxDepth(TreeNode* root) {
return maxp;
}
回看上图中的二叉树
5
/ \
3 8
/ / \
2 7 9
/ /
1 6
当传入5这个节点(注意:传入的是节点root,而不是整数5)的时候,需要返回整数4(5-3-2-1或5-8-7-6)。
那么这个4是怎么得来的呢?
其实是当我们找5这个节点的深度时,相当于去找 “3这个节点” 和 “8这个节点” 的深度,因为当我们知道了这个两个节点为根节点时的深度,那么找到这两个里长度最长的那一条路径的长度再加上1,就是以5为根节点时的深度。
现在问题转化为了,如何找到 “3这个节点” 和 “8这个节点” 的树的深度,那么我们是不是依旧可以运用上述的方法,把问题转化为去找 “2这个节点” “7这个节点” “9这个节点”。
相信到这里,您已经发现问题的实质就是运用递归,逐级由上向下去找子树的深度,直到叶节点(最末端)。
定义递归函数length,传入节点,返回以传入节点为根节点时,树的深度。
定义maxp用来记录当前递归中哪条子树深度最大。
int maxp=0;//最大节点数
int length(TreeNode* root){
if(root==nullptr){
return 0;
}
int l=length(root->left);
int r=length(root->right);
maxp=max(l,r)+1;
return maxp;
}
完整代码如下
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
int maxp=0;//最大节点数
public:
int maxDepth(TreeNode* root) {
length(root);
return maxp;
}
int length(TreeNode* root){
if(root==nullptr){
return 0;
}
int l=length(root->left);
int r=length(root->right);
maxp=max(l,r)+1;
return maxp;
}
};
采用深度优先搜索,时间复杂度为O(n)。
三、求二叉树的直径
定义一个函数diameterOfBinaryTree,传入节点,返回二叉树的直径。
int diameterOfBinaryTree(TreeNode* root) {
return maxp-1;
}
相较于求解二叉树的深度,计算二叉树的直径需要同时计算根节点两侧的树的长度(或者计算节点数),因此在计算时,需要取左侧最长节点数+右侧最长节点数+1(这个根节点本身),才是最长路径的节点总数。
与深度计算同理,依旧采用递归的方法,在计算左侧(右侧)最长节点数时,用递归的方式,逐层算出,并记录最大值(因为在计算二叉树直径时,这条最长的路径未必会通过根节点,如下图:
5
/ \
3 8
/ \
2 7
/ \
1 6
/ \
9 10
(9-1-2-3-7-6-10) 共7个节点,长度为6
(9-1-2-3-5-8) 共6个节点,长度为5
因此该直径并未经过根节点 5。
如下为具体的递归函数 :
int maxp=1;//最大节点数
int length(TreeNode* root){
if(root==nullptr){
return 0;
}
// 递归
int l=length(root->left);//左子树(不算根节点)的节点数,不能设置为全局变量
int r=length(root->right);//右子树
maxp=max(maxp,l+r+1);//左+右+根
return max(l,r)+1;
}
完整代码:
int maxp=1;//最大节点数
int diameterOfBinaryTree(TreeNode* root) {
length(root);
return maxp-1;
}
int length(TreeNode* root){
if(root==nullptr){
return 0;
}
// 递归
int l=length(root->left);//左子树(不算根节点)的节点数
int r=length(root->right);//右子树
maxp=max(maxp,l+r+1);//左+右+根
return max(l,r)+1;
}