题目链接:点击这里
来一个最鲁莽的做法,码力十足
分析:
- 两个节点的公共祖先一定在从根节点至这两个节点的路径上。
- 公共祖先中的最近公共祖先,即同时出现在这两条路径上的离根节点最远的节点 (或离两个最近) 。
- 最终算法:求出p节点路径 和 q节点路径,然后找到两路径上最后一个相同的节点。
/**
* 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:
//求根节点到某结点的路径(深度遍历)
//node正在遍历的结点,search带搜索的结点,path路径栈,result存储路径结果,finish记录是否找到
void preorder(TreeNode* node, TreeNode* search, vector<TreeNode*> &path, vector<TreeNode*> &result, int &finish)
{
if(!node || finish) return;
path.push_back(node);
if(node==search)
{
finish = 1;
result = path;
}
preorder(node->left, search, path, result, finish);
preorder(node->right, search, path, result, finish);
path.pop_back();
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
vector<TreeNode*> path; //临时栈
vector<TreeNode*> node_p_path; //存储结点p的路径
vector<TreeNode*> node_q_path; //存储结点q的路径
int finish = 0;
preorder(root, p, path, node_p_path, finish);
path.clear(); //清空path、finish
finish = 0;
preorder(root, q, path, node_q_path, finish);
int path_len = 0; //较短路径的长度
if(node_p_path.size() < node_q_path.size())
path_len = node_p_path.size();
else
path_len = node_q_path.size();
//同时遍历两条路径上的结点,找到最近公共祖先
TreeNode* result = NULL;
for(int i = 0 ; i < path_len; i++)
if(node_p_path[i]==node_q_path[i])
result = node_p_path[i];
return result;
}
};
递归思路:
两个节点p,q分为两种情况:
- p和q在相同子树中
- p和q在不同子树中
从根节点遍历,递归向左右子树查询节点信息。
递归终止条件:如果当前节点为空或等于p或等于q,则返回当前节点。
- 递归遍历左右子树,如果左右子树查到节点都不为空,则表明p和q分别在左右子树中,因此,当前节点即为最近公共祖先;
- 如果左右子树其中一个不为空,则返回非空节点。
注意LeetCode迷之报错:
/**
* 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||root==p||root==q) return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if(left==NULL) return right; //如果p,q仅在右子树
else if(right==NULL) return left; //如果p,q仅在左子树
else return root; //如果p,q在左右两个子树上
}
};