为了对二叉树的知识进行巩固,今天我们来解析5道二叉树的经典面试题。
这五道面试题如下:
- 求二叉树中最远两个结点的距离;
- 判断一棵树是否是完全二叉树;
- 由前序和中序遍历序列重建二叉树 (前序序列:1 2 3 4 5 6 - 中序序列:3 2 4 1 6 5);
- 求二叉树两个结点的最近公共祖先;
将二叉搜索树转化成有序的双向链表;
现在我们来对这五道题进行分析:
求二叉树中最远的两个节点之间的距离
这道题如果没有进行全面的分析,都以为只有一下一种情况:
这时,我们只需要分别求出左右子树的高度然后相加再加1(根节点),就能得到最远的两个节点之间的距离了。
经过仔细分析,我们发现还有以下这种情况:
时间负杂度为O(N*N)的解法
当二叉树的根节点只有一颗子树时,这时候二叉树最远节点的距离应该产生在子树的左右子树高度或这棵树的高度再到根节点之间的距离两者之间的,所以我们要求一颗树最远的两个节点之间的距离,就需要求出这棵树根节点的子树的高度加上子树根节点到这棵树根节点的距离和子树中最远的两个节点之间的距离,两者的最大值就是这棵树最远的两个节点之间的距离了。所以我们要求解一棵树最远的两个节点之间的距离,就要去求子树的高度和子树的最远的两个节点之间的距离,直到我们求到子树的根节点为NULL为止。
上面这种解法运用到了二叉树先序遍历的思想,先求根节点的最远两个节点之间的距离,再去求左子树和右子树最远两个节点之间的距离。下面我们来看一种时间复杂度为O(N)的解法
时间复杂度为O(N)的解法
这种解法就需要用到二叉树后序遍历的思想了,我们碰到树的根节点先不去求当前根节点最远的两个节点之间的距离,转而去求它左右子树最远的两个节点之间的距离和左右子树的高度,最后再来求当前根节点最远的两个节点之间的距离。
我们直接给出最优解法的代码:
//时间复杂度为O(N^2)的算法
size_t DepthOfNode(BinaryTreeNode<int>* node)
{
if (node == NULL)
{
return 0;
}
//分别求左右子树
size_t Left = DepthOfNode(node->_Left) + 1;
size_t Right = DepthOfNode(node->_Right) + 1;
/*cout << "Left:"<<Left << endl;
cout << "Right:" << Right << endl;*/
return Left > Right ? Left : Right;
}
void _DisTanceOfNode(Node* root, size_t& LeftHigh, size_t RightHigh, size_t& Max);
size_t DisTanceOfNode(BinaryTree<int>& tree)
{
size_t LeftHight = 0;
size_t RightHight = 0;
size_t Max = 0;
_DisTanceOfNode(tree.ReturnRoot(), LeftHight, RightHight,Max);
return Max;
}
时间复杂度为O(N*N)的算法
void _DisTanceOfNode(Node* root, size_t& LeftHigh, size_t RightHigh,size_t& Max)
{
if (root == NULL)
return;
if (root->_Left == NULL)
LeftHigh = 0;
if (root->_Right == NULL)
RightHigh = 0;
if (root->_Left != NULL)
_DisTanceOfNode(root->_Left, LeftHigh, RightHigh, Max);
if (root->_Right != NULL)
_DisTanceOfNode(root->_Right, LeftHigh, RightHigh, Max);
LeftHigh = DepthOfNode(root->_Left);
RightHigh = DepthOfNode(root->_Right);
//更新当前根节点的最远两个节点之间的距离
if (LeftHigh + RightHigh +