找到二叉數中某兩個節點的第一個共同祖先節點。這裏給出了兩種解法,分別是常規解法和遞歸解法。
常規解法:首先從root開始,自上而下,找到p節點的所有祖先節點,然後依據從下往上的順序,判斷每一個p的祖先節點是不是q的祖先節點,如果是的話,那麼就是第一個共同祖先節點,返回
//判斷root是不是q的祖先節點
bool isancestor(TreeNode *root, TreeNode* q) {
//root爲NULL節點,終止遞歸,返回
if (root == NULL) {
return false;
}
//找到q節點,返回True,即root節點是q節點本身,也就是祖先
if (root->val == q->val) {
return true;
} else {
//如果root的左子樹或者右子樹是q的祖先結點,那麼root也是q的祖先節點
return isancestor(root->left, q) || isancestor(root->right, q);
}
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
stack<TreeNode*> nodes;
TreeNode* node = root;
//找到p的所有祖先結點,存入nodes
while (true) {
//判斷node是不是p的祖先節點
if (isancestor(node, p)) {
nodes.push(node);
} else {
break;
}
//遞歸判斷node的左子結點或者右子結點是不是p的祖先,如果是的話,就加入nodes
if (isancestor(node->left, p)) {
nodes.push(node->left);
node = node->left;
} else if (isancestor(node->right, p)) {
nodes.push(node->right);
node = node->right;
} else {
break;
}
}
//p結點本身也是祖先結點
if (node) {
nodes.push(node);
}
//判斷p的所有祖先結點,是不是q的祖先結點,如果是,則返回
while (!nodes.empty()) {
node = nodes.top();
nodes.pop();
if (isancestor(node, q)) {
return node;
}
}
return NULL;
}
遞歸解法:
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) {
//到達葉子節點,沒有找到p節點或者q節點
if (root == NULL) {
return NULL;
}
//找到了p 節點或者q節點,返回
if (root->val == p->val || root->val == q->val) {
return root;
}
//在當前節點的左子樹和右子樹遞歸尋找p、q節點
TreeNode *left = lowestCommonAncestor(root->left, p, q);
TreeNode *right = lowestCommonAncestor(root->right, p, q);
//p、q節點一個在左子樹,一個在右子樹,那麼共同祖先節點就是當前root節點
if (left && right) {
return root;
//p或q節點都在左子樹
} else if (left) {
return left;
//p或q節點都在右子樹
} else if (right) {
return right;
} else {
return NULL
}
}