[leetcode] 236.Lowest Common Ancestor of a Binary Tree
2015-08-21 11:35
316 查看
题目:
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).”
/ \ / \
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.
题意:
给定一棵二叉树,查找其中两个节点的最近公共祖先。
思路:
拿到这道题首先分析下,什么是最近公共祖先。如果A是p和q最近的公共祖先,那么分为以下四种情况:
p,q分别在A的两个子树中。
p就是A,q在A的某个子树中。
q就是A,p在A的某个子树中。
p,q都是A。
方法一:如果B是A的祖先,那么很明显B是p,q的祖先。不妨假设此时A在B的左子树中,那么很明显不满足上面四个条件之一。此时继续查看B的左右孩子,然后发现A也是左右子树的祖先,继续往下判断,发现A的两个孩子都不是p,q的公共祖先,那么就可以得到A就是最近公共祖先。总结起来这个方法就是从根节点判断,当前节点是不是p,q的祖先,如果是的话查看当前节点的孩子是不是p,q的公共祖先,如果当前节点是p,q的公共祖先,但是它的所有孩子都不是,那么就可以断定当前节点就是最近公共祖先。不过这个方法的一个问题就是会去重复查找p,q是否是其子孙。比如对于当前节点能够访问到p的路径是A->B->C->D->p,同理访问q是A->B->C->E->q,那么接下里要去查看B是不是两个孩子的路径,又会访问B->C->D->p, B->C->E->q,其实这条路径之前已经走过,但是每次却在重复通过这些路径查找。
方法二:
所以我们需要进行方法的改良,我们可以从根节点保存访问到p以及q的路径。比如以上所说的A->B->C->D->p和A->B->C->E->q,那么从根节点依次往后扫描,到最后一个相同的元素(C),就是两个点的最近公共祖先。这道题目需要额外的空间平均情况是O(lgn),最坏是O(n),
综上,就是先找到根节点到两个节点的路径,然后找到路径上最后一个共同的节点。
以上。
代码如下:
方法三:
以上需要保存额外的空间,那么能否不需要保存从根节点到p,q的路径呢?答案是肯定的。采用递归的方法,
1.如果当前节点的左子树中找到了最近祖先,ok,直接返回。
2.如果左子树没找到,但是右子树找到了,ok继续直接返回。
3.如果左右子树都没找到最近祖先,那么有可能当前节点就是公共祖先(为什么是可能呢,因为如果p或者q有一个或者两个根本就不在树中,那自然不能说当前节点就是公共祖先了)。
4.如果左右子树各找到p,q中的一个,那么当前节点就是最近祖先。
5.如果两边一个都没找到,但是当前节点root==p==q,那么当前节点也确实就是最近祖先节点。
6.否则就是返回NULL,找不到最近祖先。
我们在递归的函数中,加入一个保存最近祖先的值。这样就可以帮助判断是否已经找到了最近祖先,找到了就直接返回啦。
以上。
代码如下:
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.
题意:
给定一棵二叉树,查找其中两个节点的最近公共祖先。
思路:
拿到这道题首先分析下,什么是最近公共祖先。如果A是p和q最近的公共祖先,那么分为以下四种情况:
p,q分别在A的两个子树中。
p就是A,q在A的某个子树中。
q就是A,p在A的某个子树中。
p,q都是A。
方法一:如果B是A的祖先,那么很明显B是p,q的祖先。不妨假设此时A在B的左子树中,那么很明显不满足上面四个条件之一。此时继续查看B的左右孩子,然后发现A也是左右子树的祖先,继续往下判断,发现A的两个孩子都不是p,q的公共祖先,那么就可以得到A就是最近公共祖先。总结起来这个方法就是从根节点判断,当前节点是不是p,q的祖先,如果是的话查看当前节点的孩子是不是p,q的公共祖先,如果当前节点是p,q的公共祖先,但是它的所有孩子都不是,那么就可以断定当前节点就是最近公共祖先。不过这个方法的一个问题就是会去重复查找p,q是否是其子孙。比如对于当前节点能够访问到p的路径是A->B->C->D->p,同理访问q是A->B->C->E->q,那么接下里要去查看B是不是两个孩子的路径,又会访问B->C->D->p, B->C->E->q,其实这条路径之前已经走过,但是每次却在重复通过这些路径查找。
方法二:
所以我们需要进行方法的改良,我们可以从根节点保存访问到p以及q的路径。比如以上所说的A->B->C->D->p和A->B->C->E->q,那么从根节点依次往后扫描,到最后一个相同的元素(C),就是两个点的最近公共祖先。这道题目需要额外的空间平均情况是O(lgn),最坏是O(n),
综上,就是先找到根节点到两个节点的路径,然后找到路径上最后一个共同的节点。
以上。
代码如下:
/** 1. Definition for a binary tree node. 2. struct TreeNode { 3. int val; 4. TreeNode *left; 5. TreeNode *right; 6. TreeNode(int x) : val(x), left(NULL), right(NULL) {} 7. }; */ class Solution { public: TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { if(root == NULL || p == NULL || q == NULL) return NULL; vector<TreeNode*> pv, qv; if(!(getPath(root, p, pv) && getPath(root, q, qv)))return NULL; return getCommonAncestor(pv, qv); } bool getPath(TreeNode* root, TreeNode* p, vector<TreeNode*>& elements) { elements.push_back(root); if(root == p) { return true; } if(root->left != NULL) { if(getPath(root->left, p, elements))return true; } if(root->right != NULL) { if(getPath(root->right, p, elements))return true; } elements.pop_back(); return false; } TreeNode* getCommonAncestor(vector<TreeNode*> pv, vector<TreeNode*> qv) { TreeNode* last = NULL; int index = 0; int sp = pv.size(); int sq = qv.size(); while(index < sp && index < sq && pv[index] == qv[index]) { last = pv[index]; index++; } return last; } };
方法三:
以上需要保存额外的空间,那么能否不需要保存从根节点到p,q的路径呢?答案是肯定的。采用递归的方法,
1.如果当前节点的左子树中找到了最近祖先,ok,直接返回。
2.如果左子树没找到,但是右子树找到了,ok继续直接返回。
3.如果左右子树都没找到最近祖先,那么有可能当前节点就是公共祖先(为什么是可能呢,因为如果p或者q有一个或者两个根本就不在树中,那自然不能说当前节点就是公共祖先了)。
4.如果左右子树各找到p,q中的一个,那么当前节点就是最近祖先。
5.如果两边一个都没找到,但是当前节点root==p==q,那么当前节点也确实就是最近祖先节点。
6.否则就是返回NULL,找不到最近祖先。
我们在递归的函数中,加入一个保存最近祖先的值。这样就可以帮助判断是否已经找到了最近祖先,找到了就直接返回啦。
以上。
代码如下:
/** * 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; TreeNode* result = new TreeNode(0); result = NULL; getAncestor(root, p, q, &result); return result; } TreeNode* getAncestor(TreeNode* root, TreeNode* p, TreeNode* q, TreeNode** ancestor) { if (*ancestor != NULL)return *ancestor; if (root == NULL)return NULL; if (root == p && root == q) { *ancestor = root; return root; } TreeNode* res1 = getAncestor(root->left, p, q, ancestor); if (*ancestor != NULL)return *ancestor; TreeNode* res2 = getAncestor(root->right, p, q, ancestor); if (*ancestor != NULL)return *ancestor; if (res1 != NULL && res2 != NULL) { *ancestor = root; return *ancestor; } else if (res1 != NULL || res2 != NULL) { if (root == p || root == q) { *ancestor = root; return *ancestor; } else return(res1 == NULL) ? res2 : res1; } else if (root == p || root == q)return root; return NULL; } };
相关文章推荐
- 从request中获取上一个请求的url
- Gauss消去法求线性方程组
- Codeforces Round #152 (Div. 2) D. Sweets for Everyone!(二分)
- 洛谷1003 铺地毯 解题报告
- 无重复元素的排列
- HDOJ 1599 find the mincost route(floyd 最小环,模板)
- 随遇而安来自心甘情愿
- androoid makefile 学习
- 【SpringMVC整合MyBatis】提供学习参考的项目源码
- IE6 、IE7 、 IE8 的 CSS 、 JS 兼容
- JPA 继承方式
- 金槌しか持っていなければ、すべての問題は釘に見えてくる
- hdu 3460
- 解决AngularJS使用ng-bind-html会过滤html中style属性的问题
- 一点一点学习struts1(一)_简介
- 迭代器iterator
- UIButton透明度
- python基础之使用os.system来执行系统命令
- ListView setCacheColorHint 性能影响
- 面向对象的编程的实施例