在二叉树中找最近公共父节点。分为两种情况,一种是有父指针,一种没有父指针。
1、有父指针
这种情况比较简单,计算两个结点的深度,再把深度大的向上移,移到同一深度。在同时向上移动,直到两个结点相同,这样便找到了父节点。这个算法时间复杂度为O(N)。
代码实现:
- #include<iostream>
- struct Node
- {
- int data;
- Node* left;
- Node* right;
- Node* parent;
- Node() :left(NULL), right(NULL), parent(NULL)
- {}
- };
- int getDpeth(Node *n)
- {
- int count = 0;
- while (n)
- {
- ++count;
- n = n->parent;
- }
- return count;
- }
- Node* findNearestCommonAncestor(Node* n1, Node* n2)
- {
- int depth1 = getDpeth(n1);
- int depth2 = getDpeth(n2);
-
-
- while (depth1 > depth2)
- {
- n1 = n1->parent;
- --depth1;
- }
- while (depth1 < depth2)
- {
- n2 = n2->parent;
- --depth2;
- }
-
- while (n1 != n2)
- {
- n1 = n1->parent;
- n2 = n2->parent;
- }
- return n1;
- }
-
- int main()
- {
-
- Node* A[11];
- for (int i = 0; i < 11; ++i)
- {
- A[i] = new Node();
- A[i]->data = i;
- }
-
- for (int i = 0; i < 5; ++i)
- {
- A[i]->left = A[i * 2 + 1];
- A[i * 2 + 1]->parent = A[i];
-
- A[i]->right = A[i * 2 + 2];
- A[i * 2 + 2]->parent = A[i];
- }
-
- Node* Ancestor = findNearestCommonAncestor(A[7], A[6]);
-
-
- }
2、没有父指针
这种情况有点难。首先从根节点开始向下找,如果根节点等于其中一个子节点,那么根节点便是最近公共父结点。否则计算左子树和右子树中包含n1或n2的个数。如果左子树包含n1、n2那么最近公共父结点在左子树,如果右子树包含n1和n2,那么在右子树。如果左右子树各包含一个,那么最近公共父结点就是当前结点。如果二叉树是平衡的,那么算法复杂度为O(logN)。最坏情况就是树成了链表,算法时间负责度为O(N^2)。
思路清晰了,可以编写代码:
- #include<iostream>
- struct Node
- {
- int data;
- Node* left;
- Node* right;
- Node() :left(NULL), right(NULL)
- {}
- };
-
- int countMatch(Node *current, Node* n1, Node* n2)
- {
- if (current == NULL)
- return 0;
- int count = countMatch(current->left, n1, n2) + countMatch(current->right, n1, n2);
- if (current == n1 || current == n2)
- return 1 + count;
- return count;
- }
- Node* findLCA(Node* root, Node* n1, Node* n2)
- {
- if (root == NULL)
- return NULL;
- if (root == n1 || root == n2)
- return root;
- int count = countMatch(root->left, n1, n2);
- if (count == 1)
- return root;
- else if (count == 2)
- return findLCA(root->left, n1, n2);
- else
- return findLCA(root->right, n1, n2);
- }
- int main()
- {
-
- Node* A[11];
- for (int i = 0; i < 11; ++i)
- {
- A[i] = new Node();
- A[i]->data = i;
- }
-
- for (int i = 0; i < 5; ++i)
- {
- A[i]->left = A[i * 2 + 1];
-
- A[i]->right = A[i * 2 + 2];
-
- }
-
- Node* Ancestor = findLCA(A[0],A[7], A[10]);
-
-
- }
还有一种方法,从下向上找。如果找到n1或n2,就把它传给它的父结点,如果向下到头都没有找到,那么返回NULL。如果当前结点左右子树都返回非NULL,那么当前结点就是最近公共父结点。这样只需要遍历一遍,算法时间复杂度为O(N)。
- #include<iostream>
- struct Node
- {
- int data;
- Node* left;
- Node* right;
- Node() :left(NULL), right(NULL)
- {}
- };
- Node* findLCA(Node *root, Node* n1, Node* n2)
- {
- if (root == NULL)
- return NULL;
- if (root == n1 || root == n2)
- return root;
- Node* L = findLCA(root->left, n1, n2);
- Node* R = findLCA(root->right, n1, n2);
-
- if (L != NULL&R != NULL)
- return root;
-
- else
- return L !=NULL ? L : R;
- }
-
- int main()
- {
-
- Node* A[11];
- for (int i = 0; i < 11; ++i)
- {
- A[i] = new Node();
- A[i]->data = i;
- }
-
- for (int i = 0; i < 5; ++i)
- {
- A[i]->left = A[i * 2 + 1];
-
- A[i]->right = A[i * 2 + 2];
-
- }
-
- Node* Ancestor = findLCA(A[0], A[7], A[10]);
-
-
- }