Leetcode 236. 二叉树的最近公共祖先
解法1:
解法1借鉴于力扣官方解法,这里只是记录一下
二叉树的最近公共祖先一共有三种情况:
1. p或者q在左子树
2. p或者q在右子树
3. 根自己就是p或者q,则另一个p或q在左子树中或是右子树中
记左子树为, 则右子树为,上述情况可表达为:
根据上面表达式,可以确定公共祖先。
当左子树包含p或q时,左子树为真,当右子树包含p或q时,右子树为真,根为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: TreeNode* ans; bool dfs(TreeNode* root, p, q) { if(root == NULL) return false; bool left = dfs(root->left,p,q); bool right = dfs(root->right,p,q); if((left&&right)||((root->val == p||root->val == q)&&(left||right)) ans = root; return (left||right||(root->val == p || root-val == q); } TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { dfs(root,p,q); return ans; } };
解法二:
通过p和q的路径去找,两种情况
1. 当p和q不在同一路径上,p和q在左子树或是右子树里。
2. 当p和q在同一路径上时,p和q有一个为根节点。
第一种情况,找到p的路径和q的路径,找到二者路径不同前的最后一个相同的节点,即为最近公共祖先。
第二种情况,同样找到二者的路径,p和q最后一个相同的节点即为最近公共祖先。
这里可以借用栈来实现。
解法三:
利用递归的解法。
首先明确基本情况是
1. 当递归到为空时,肯定返回空。
2. 当找到了p或者q时,直接返回这个节点。
可以写出基本的代码,也就是函数的出口。
递归去返回左边和右边的情况,这里用后序遍历的时机,也就是说当子树已经知道自己是什么情况的时候,往上逐层去返回。
分别从左边去递归和从右边去递归,左边要不然找到p或者q,要不然为空,右边也是一样。
每个子树知道了自己的情况后,该怎么向上面汇报呢,或者说汇报什么呢,左右子树又有四种情况:
1. 左右子树都为空,自然返回空;
2. 左右子树都不为空,找到了!返回root;
3. 左边不为空右边为空,返回左边的;
4. 右边不为空左边为空,返回右边的;
最后两种情况可以综合一下,哪边不为空返回哪边的。
所以可以写出如下的代码:
/** * 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) return root; if(root == q || root == p) return root; TreeNode* ltree = lowestCommonAncestor(root->left, p,q); TreeNode* rtree = lowestCommonAncestor(root->right,p,q); if(ltree == NULL && rtree == NULL) return NULL; if(ltree!= NULL && rtree!= NULL) return root; //if(ltree == NULL || rtree == NULL) return ltree == NULL ? rtree : ltree; } };