寻找二叉树两节点的最近的公共祖先

1.树节点定义中带有parent指针

struct TreeNode
{
int data;
TreeNode *left,*right,*parent;
};

算法思想:

(1). p->parent

(2). 将q的所有祖先节点依次和p->parent作比较,如果发现两个节点相等,则该节点就是最近公共祖先,直接将其返回。如果没找到相等节点,则转3

(3).p = p->parent,转2

主要代码如下:

const TreeNode* FindNCA(const TreeNode* root,const TreeNode* p,const TreeNode* q)
{
    if(root==NULL || p==NULL || q==NULL)
        return NULL;
    while(p)
    {
        p = p->parent;
        const TreeNode* tmp = q;
        while(tmp)
        {
            if(p == tmp->parent)
                return p;
            tmp = tmp->parent;
        }
    }
}
void TestNCA()
{
    TreeNode *root  = newTreeNode(2);
    TreeNode *p1 = newTreeNode(1);
    root->left = p1;
    p1->parent = root;
    TreeNode *p4 = newTreeNode(4);
    root->right = p4;
    p4->parent = root;
    TreeNode *p3 = newTreeNode(3);
    root->right->left  = p3;
    p3->parent = root->right;
    TreeNode *p5 = newTreeNode(5);
    root->right->right = p5;
    p5->parent = root->right;
//    Constructed binary search tree is
//            2
//           / \
//         1   4
//             / \
//           3   5
    const TreeNode* out = FindNCA(root,p1,p5);
    if(out) printf("\nResult pointer is %d", out->data);
    else printf("\nNot find pointer");
}

时间复杂度:假设p,q的公共父节点为cur,p到cur的路径长度为LP,q到cur的路径长度LQ, 则时间复杂度为O(LP*LQ).空间复杂度O(1).


另外一种可能会降低时间复杂度的方法:

算法思想:

(1). 从root到p建立一条链表list1,从root到q建立一条链表list2

(2). 问题转为为求list1和list2的最后一个相同的节点

主要代码如下

struct Node //链表节点
{
Node* next;
int data;
};
bool PushFront(Node** phead, int data)
{
Node* newNode = new Node;
if(newNode == NULL) return false;
newNode->data = data;
newNode->next = *phead;//无论*phead是否为空都行
*phead = newNode;
return true;
}
const Node* FindLastSameNode(const Node* head1,const Node* head2)
{
if(head1==NULL || head2==NULL)
return NULL;
const Node* prev1 = NULL;
//本来应该写成head1==head2,但是这里的实现不大好
while(head1 && head2 && head1->data==head2->data)
{
prev1 = head1;
head1 = head1->next;
head2 = head2->next;
}
return prev1;
}
const Node* FindNCA(const TreeNode* root,const TreeNode* p,const TreeNode* q)
{
if(root==NULL || p==NULL || q==NULL)
return NULL;
Node *list1=NULL, *list2=NULL;
while(p != NULL)
{
PushFront(&list1,p->data);
p = p->parent;
}
//cout<<endl;
while(q != NULL)
{
PushFront(&list2,q->data);
q = q->parent;
}
//cout<<"\nlist1: ";Print(list1); //for debug
//cout<<"\nlist2: ";Print(list2); //for debug
return FindLastSameNode(list1, list2);
}
void TestNCA()
{
TreeNode *root = newTreeNode(2);
TreeNode *p1 = newTreeNode(1);
root->left = p1;
p1->parent = root;
TreeNode *p4 = newTreeNode(4);
root->right = p4;
p4->parent = root;
TreeNode *p3 = newTreeNode(3);
root->right->left = p3;
p3->parent = root->right;
TreeNode *p5 = newTreeNode(5);
root->right->right = p5;
p5->parent = root->right;
// Constructed binary search tree is
// 2
// / \
// 1 4
// / \
// 3 5
const Node* out = FindNCA(root,p1,p5);
if(out) printf("\nResult pointer is %d", out->data);
else printf("\nNot find pointer");
}

时间复杂度分析:假设p节点到根节点的路径长度为L1,假设q节点到根节点的路径长度为L2,则算法的时间复杂度为O(L1+L2),空间复杂度小于O(L1+L2).

2.树节点定义中不带有parent指针

主要思想:节点cur的左子树包含一个节点(p或者q),右子树包含另一个节点(p或者q),则cur就是我们要找的节点。

//不带parent指针的树节点
struct TreeNode
{
int data;
TreeNode *left,*right;
};

TreeNode* newTreeNode(int data)
{
TreeNode* node = new TreeNode;
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}

//返回root为根的树种包含p,q两个节点中节点的数目:0,1,2
int FindNCA(TreeNode* root,const TreeNode* p,const TreeNode* q,TreeNode** out)
{
if(root==NULL) return 0;
if(root==p || root==q) return 1;
int iLeft = FindNCA(root->left,p,q,out);
if(iLeft==2) return 2;
int iRight = FindNCA(root->right,p,q,out);
if(iRight==2) return 2;
if(iLeft+iRight==2) *out = root;
return iLeft+iRight;
}

void TestNCA()
{
TreeNode *root = newTreeNode(2);
TreeNode *p1 = newTreeNode(3);
root->left = p1;
TreeNode *p4 = newTreeNode(3);
root->right = p4;
TreeNode *p3 = newTreeNode(3);
root->right->left = p3;
TreeNode *p5 = newTreeNode(5);
root->right->right = p5;
// Constructed binary search tree is
// 2
// / \
// 1 4
// / \
// 3 5
TreeNode* out = NULL;
int i = FindNCA(root, p1, p5, &out);
if( i == 2 ) printf("Result pointer is %d", out->data);
else printf("Not find pointer");
}

时间复杂度分析:设书中节点的数目为N(遍历所有的树节点),则时间复杂度为O(N),空间复杂度O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值