LowestCommonAncestor
- 問題描述:給定一顆二叉樹,和二叉樹的兩個節點,計算出這兩個節點的最低公公祖先。
- 解法1:
- 最低公公祖先可能出現的最高值就是根節點。
- 我們找到從根節點到兩個節點的路徑,path1和path2.
- 則兩者一定是Y字型或者是V字形(root節點)
- 則我們就把問題轉化成了計算兩個list的相交點問題。
- 首先長的path先走他們之間長度差值步,使得後續的兩個path長度一致。
- 然後再同時向後走,第一個相遇的點就是LCA
- 解法2 (DP):
- 拆分子問題:我們可以判斷左子樹和右子樹是否包含這兩個節點其中的一個。
- 構造父問題:如果左子樹和右子樹都包含兩個節點中的一個,則返回當前的根節點。如果只有左子樹包含,則返回左子樹的根節點,如果只有右子樹包含,則返回右子樹的根節點。
- 代碼
bool findPath(TreeNode* root, TreeNode* target, vector<TreeNode*>& path){
if(root == NULL){
return false;
}
if(root == target){
path.push_back(root);
return true;
}
bool left_res = findPath(root->left, target, path);
if(left_res){
path.push_back(root);
return true;
}
bool right_res = findPath(root->right, target, path);
if(right_res){
path.push_back(root);
return true;
}
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL)
return NULL;
vector<TreeNode*> path_p, path_q;
findPath(root, p, path_p);
findPath(root, q, path_q);
if(path_p.empty() || path_q.empty())
return NULL;
int size_p = (int) path_p.size();
int size_q = (int) path_q.size();
int start_p = 0;
int start_q = 0;
if(size_p >= size_q){
start_p = size_p - size_q;
}else{
start_q = size_q - size_p;
}
for(;start_p < size_p && start_q < size_q;start_p++, start_q++){
if(path_p[start_p] == path_q[start_q])
return path_p[start_p];
}
return NULL;
}
TreeNode* lowestCommonAncestorV2(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root || root == p || root == q)
return root;
TreeNode* left = lowestCommonAncestorV2(root->left, p, q);
TreeNode* right = lowestCommonAncestorV2(root->right, p, q);
return left == NULL ? right: right == NULL ? left : root;
}