求二叉树中两个节点的最近公共祖先节点
思路1:
- 如果两个节点在左右子树,最近的就是他们的根结点
- 两个节点在同一侧,用子问题方法求解
BTreeNode * Find(BTreeNode *root, TDataType data)
{
if(root == NULL)
{
return NULL;
}
if(root->data == data)
{
return root;
}
BTreeNode *result = Find(root->left, data);
if (result != NULL)
{
return result;
}
result = Find(root->right, data);
if (result != NULL)
{
return result;
}
else
{
return NULL;
}
}
BTreeNode * GetAncestor(BTreeNode *root, BTreeNode *node1, BTreeNode *node2)
{
BTreeNode *node1InLeft = Find(root->left, node1->data);
BTreeNode *node2InLeft = Find(root->left, node2->data);
BTreeNode *node1InRight = Find(root->right, node1->data);
BTreeNode *node2InRight = Find(root->right, node2->data);
if((node1InLeft && node2InLeft) || (node1InRight && node2InRight))
{
return root;
}
if (node1InLeft) {
return GetAncestor(root->left, node1, node2);
}
else {
return GetAncestor(root->right, node1, node2);
}
}
思路2:(这里我用C++写出,题目源自leetcode:236)
- 通过非递归的后序遍历,找到从根到结点的路径保存在栈里
- 用类似链表交叉求交点的思路,找到最近的公共祖先
/**
* Definition for a binary tree node.
* struct BTreeNode {
* int val;
* BTreeNode *left;
* BTreeNode *right;
* BTreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool getAncestor(BTreeNode* root, BTreeNode* p, stack<BTreeNode*>& sta){
if(root == NULL){
return false;
}
if(root == p){
sta.push(root);
return true;
}
if(getAncestor(root->left,p,sta)||getAncestor(root->right,p,sta)){
sta.push(root);
return true;
}
return false;
}
TreeNode* lowestCommonAncestor(BTreeNode* root, BTreeNode* p, BTreeNode* q) {
stack<BTreeNode*> pstack,qstack;
getAncestor(root,p,pstack);
getAncestor(root,q,qstack);
BTreeNode* top = NULL;
while(!pstack.empty() && !qstack.empty() && qstack.top() == pstack.top()){
top = qstack.top();
pstack.pop();
qstack.pop();
}
return top;
}
};
判断一颗二叉树是否是平衡二叉树
思路:
- 左子树是否平衡&&右子树是否平衡
- 高度差不能超过1
- 空树/只有一个节点的树 是平衡树
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int GetHeight(BTreeNode* root)
{
if (root == NULL) {
return 0;
}
return MAX(GetHeight(root->left), GetHeight(root->right)) + 1;
}
bool IsBalanceTree(BTreeNode* root)
{
if(root == NULL)
{
return true;
}
//左子树是否平衡
if(!(IsBalanceTree(root->left)))
{
return false;
}
//右子树是否平衡
if(!(IsBalanceTree(root->right)))
{
return false;
}
//计算高度
int leftHeight = GetHeight(root->left);
int rightHeight = GetHeight(root->right);
int heigth = leftHeight - rightHeight;
if(height >= -1 && height <= 1)
{
return true;
}
return false;
}
- 进阶版(省掉求高度的函数)
#define MAX(a, b) ((a) > (b) ? (a) : (b))
bool IsBalanceAd(BTreeNode *root, int *pHeight)
{
if(root == NULL)
{
*pHeight = 0;
return true;
}
int leftHeight;
if (!(IsBalanceAd(root->left, &leftHeight))) {
// 左子树不平衡,没必要继续,整棵树一定不平衡
*pHeight = -1; // 不平衡的情况,高度没有用,给的值无意义
return false;
}
// 判断右子树是否平衡
int rightHeight;
if (!(IsBalanceAd(root->right, &rightHeight))) {
// 右子树不平衡,没必要继续,整棵树一定不平衡
*pHeight = -1; // 不平衡的情况,高度没有用,给的值无意义
return false;
}
// 真正的整棵树的高度
*pHeight = MAX(leftHeight, rightHeight) + 1;
// 高度差不超过 1
int height = leftHeight - rightHeight;
if (height >= -1 && height <= 1) {
return true;
}
return false;
}
求二叉树中最远的两个节点的距离
思路:
- 左子树最远距离
- 右子树最远距离
- 经过根的最远距离 = 左子树高度 + 右子树高度
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int GetLongDistance(BTreeNode* root, int* maxLeft, int* maxRight)
{
if(root == NULL)
{
maxLeft = 0;
maxRight = 0;
return 0;
}
int maxLoL,maxLoR,maxRoL,maxRoR;//左子树:向左最大,向右最大;右子树:向左最大,向右最大
int leftLD,rightLD;
if(root->left != NULL)
{
leftLD = GetLongDistance(root->left, &maxLoL, &maxLoR);
maxLeft = MAX(maxLoL, maxLoR) + 1;
}
else
{
leftLD = 0;
maxLeft = 0
}
if(root->right != NULL)
{
rightLD = GetLongDistance(root->right, &maxRoL, &maxRoR);
maxRight = MAX(maxRoL, maxRoR) + 1;
}
else
{
rightLD = 0;
maxRight = 0
}
return MAX(MAX(leftLD,rightLD) , maxLeft + maxRight);
}
有前序遍历和中序遍历重建二叉树(前序遍历结果:1,2,3,4,5,6 中序遍历结果:4,2,5,1,6,3)
思路:
- 从前序取根的值:第一个元素总是树的根节点的值
- 中序遍历序列中,找到根节点的下标:左子树的节点的值位于根节点的值的左边,右子树的节点的值位于根节点的值的右边。
- 递归建立二叉树
typedef struct BTreeNode {
int data;
struct BTreeNode *left;
struct BTreeNode *right;
} BTreeNode;
BTreeNode * CreateNode(int data)
{
BTreeNode *node = (BTreeNode *)malloc(sizeof(BTreeNode));
assert(node);
node->data = data;
node->left = node->right = NULL;
return node;
}
BTreeNode * CreateTree(int* preOrder, int* inOrder, int size)
{
if(size <= 0)
{
return NULL;
}
// 从前序取根的值
int rootValue = preOrder[0];
// 从中序中找到根的下标
int rootIndexInOrder = -1;
for (int i = 0; i < size; i++) {
if (inOrder[i] == rootValue) {
rootIndexInOrder = i;
}
}
assert(rootIndexInOrder != -1);
// rootIndexInOrder 既是根在中序中的下标,也是左子树结点的个数
BTreeNode* newRoot = CreateNode(rootValue);
newRoot->left = CreateTree(preOrder+1, inOrder, rootIndexInOrder);
newRoot->right = CreateTree(preOrder+1+rootIndexInOrder, inOrder + 1 + rootIndexInOrder, size-rootIndexInOrder-1);
return root;
}