Lowest Common Ancestor of a Binary Tree Total Accepted: 6162 Total Submissions: 23311 My Submissions Question Solution
Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”
_______3______
/ \
___5__ ___1__
/ \ / \
6 _2 0 8
/ \
7 4
For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.
正確的做法:
檢查一個節點是否同時包含需要檢查的兩個節點,如果包含那麼繼續檢查他的左右孩子,如果孩子節點不同時包含這兩個節點,那麼根節點就是最小祖先節點
這裏雖然遍歷會帶來很多重複的檢查,但是這裏可以很好的排出一種情況,就是子節點中有一些相同的節點數量
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
TreeNode *result = NULL;
findLCA(root, p, q, &result);
return result;
}
private:
bool findNode(TreeNode *root, TreeNode *p)
{
if (root == NULL || p == NULL)
{
return false;
}
if (root == p)
{
return true;
}
return findNode(root->left, p) || findNode(root->right, p);
}
int findLCA(TreeNode *root, TreeNode *p, TreeNode *q, TreeNode **result)
{
if (root == NULL)
{
return 0;
}
if (root == p)
{
if (findNode(root, q))
{
*result = root;
return 2;
}
else
{
return 1;
}
}
else if (root == q)
{
if (findNode(root, p))
{
*result = root;
return 2;
}
else
{
return 1;
}
}
else
{
int left = findLCA(root->left, p, q, result);
int right = 0;
if (left != 2)
{
right = findLCA(root->right, p, q, result);
}
if (left == 1 && right == 1)
{
*result = root;
}
return left + right;
}
}
};
這裏首先是完成了一個常規的尋找最小父親節點的算法,但是有一個測試樣例沒有辦法通過,這裏的思路是,從根節點開始查找到包含需要檢測的節點的路徑,最後變化爲尋找最大公共節點的問題,但是如果出現重複的節點就不能想象哪個路徑是正確的
如果數中有重複的node那麼,必須尋找到最小的父親節點
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
if(root == NULL || p == NULL || q == NULL)
{
return NULL;
}
vector<TreeNode *> path1;
path1.clear();
GetNodePath(root,p,path1);
vector<TreeNode *> path2;
path2.clear();
GetNodePath(root,q,path2);
return FoundCommon(path1,path2);
}
int GetNodePath(TreeNode *root,TreeNode *node,vector<TreeNode *> &path)
{
if(root == NULL)
{
return 0;
}
if(root->val == node->val)
{
path.push_back(root);
return 1;
}
int found = 0;
path.push_back(root);
found = GetNodePath(root->left,node,path);
if(found == 1)
{
return 1;
}
found = GetNodePath(root->right,node,path);
if(found == 1)
{
return 1;
}
else
{
path.pop_back();
return 0;
}
}
TreeNode * FoundCommon(vector<TreeNode *> path1,vector<TreeNode *> path2)
{
if(path1.empty() || path2.empty() || path1[0] != path2[0])
{
return NULL;
}
int i = 1;
int j = 1;
TreeNode *Root = path1[0];
while(i < path1.size() && j < path2.size())
{
if(path1[i]->val == path2[j]->val)
{
Root = path1[i];
i++;
continue;
}
else
{
return Root;
}
}
return Root;
}
};
根據上面的問題,在尋找路徑的過程中將所有中間的值保留,結果進行比較輸出,然後找到路徑深度最大的那個節點:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
{
if(root == NULL || p == NULL || q == NULL)
{
return NULL;
}
vector<TreeNode *> path1;
vector<vector<TreeNode *>> tempPath1;
path1.clear();
GetNodePath(root,p,path1,tempPath1);
vector<TreeNode *> path2;
vector<vector<TreeNode *>> tempPath2;
path2.clear();
GetNodePath(root,q,path2,tempPath2);
return Found(tempPath1,tempPath2);
}
void GetNodePath(TreeNode *root,TreeNode *node,vector<TreeNode *> &path,vector<vector<TreeNode *>> &tempPath)
{
if(root == NULL)
{
return;
}
if(root->val == node->val)
{
path.push_back(root);
tempPath.push_back(path);
return;
}
path.push_back(root);
GetNodePath(root->left,node,path,tempPath);
GetNodePath(root->right,node,path,tempPath);
path.pop_back();
return;
}
TreeNode * Found(vector<vector<TreeNode *>> &tempPath1,vector<vector<TreeNode *>> &tempPath2)
{
if(tempPath1.empty() || tempPath2.empty())
{
return NULL;
}
int i = 1;
int j = 1;
int ii = 0;
int jj = 0;
int maxLength = 1;
TreeNode * min = tempPath1[0][0];
TreeNode * Root = tempPath1[0][0];
int findFlag = 0;
for(; i < tempPath1.size(); i++)
{
for(; j < tempPath2.size();j++)
{
ii = 0;
findFlag = 0;
while(ii < tempPath1[i].size() && ii < tempPath2[j].size())
{
if(tempPath1[i][ii]->val == tempPath2[j][ii]->val)
{
Root = tempPath1[i][ii];
ii++;
}
else
{
if((ii > maxLength) && (!findFlag))
{
maxLength = ii;
min = Root;
findFlag = 1;
}
}
}
}
}
return min;
}
};
其實這個問題,還有很多後續的思考:
比如:如果樹是二叉搜索樹,那麼直接利用遞歸操作就能比較好的找到節點
如果樹有父親節點,那麼可以反相構建到根節點的路徑,尋找第一個公共自節點
同理,如果是完全二叉樹,那麼也就很容易知道父親節點。。。