赞
踩
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
方法一:
1.对于二叉树,从根开始搜索,查找两个子节点的位置
(1)都在左子树,递归到左子树去找
(2)都在右子树,递归到右子树去找
(3)一个节点在左子树,一个节点在右子树,那么根就是最近公共祖先
2.找节点时,用指针去找,不能用值去找,因为有可能二叉树中存在值相等的节点
由于方法一在极端情况下复杂度为O(N^2)
因此可以使用下面的方法将时间复杂度优化为O(N)
方法二 借助栈存节点路径,假如要找6和4的最近公共祖先:
(1)从最左开始,找6:
3不是6,有可能是6的路径上的节点,入栈,
5不是6,有可能是6的路径上的节点,入栈
6,找到了,入栈
(2)从最左开始,找4:
3不是4,有可能是4的路径上的节点,入栈
5不是4,有可能是4的路径上的节点,入栈
6不是4,有可能是4的路径上的节点,入栈
6是叶子节点,这条路径上不可能有4,6出栈
2不是4,有可能是4的路径上的节点,入栈
7不是4,有可能是4的路径上的节点,入栈
7是叶子节点,这条路径上不可能有4,7出栈
4找到了,入栈
(3)确定长栈和短栈,让长栈先走差距步,然后长短栈一起走,找相同的栈顶元素
方法一:
- /**
- * 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:
- bool Find(TreeNode* root,TreeNode* x)
- {
- if(root == nullptr)
- {
- return false;
- }
-
- if(x == root)
- {
- return true;
- }
-
- return Find(root->left,x)||Find(root->right,x);
- }
-
- TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
-
- if(p == root || q == root)
- {
- return root;
- }
-
- //题目已经说明p和q一定在树中
- bool ispInLeft,ispInRight,isqInLeft,isqInRight;
-
- //如果p不在左子树,那么p一定在右子树
- //不需要在左右子树中都查找p,只需要在左子树中查找p
- ispInLeft = Find(root->left,p);
- printf("ispInLeft = %d\n",ispInLeft);
- ispInRight = !ispInLeft;
-
- //如果q不在左子树,那么q一定在右子树
- //不需要在左右子树中都查找q,只需要在左子树中查找q
- isqInLeft = Find(root->left,q);
- printf("isqInLeft = %d\n",isqInLeft);
- isqInRight = !isqInLeft;
-
- if(ispInLeft && isqInLeft)//p和q都在左子树中,就去左子树中找
- {
-
- return lowestCommonAncestor(root->left,p,q);
-
- }
- else if(ispInRight && isqInRight)//p和q都在右子树中,就去右子树中找
- {
- return lowestCommonAncestor(root->right,p,q);
- }
- else//一个在左子树,一个在右子树,根就是公共祖先
- {
- return root;
- }
- }
- };
方法二:
- class Solution {
- public:
- //找节点所在路径
- bool FindPath(TreeNode* root,TreeNode* x,stack<TreeNode*>& path)
- {
- if(root == nullptr)
- {
- return false;
- }
-
- path.push(root);
-
- if(root == x)
- {
- return true;
- }
-
- if(FindPath(root->left,x,path))
- {
- return true;
- }
-
- if(FindPath(root->right,x,path))
- {
- return true;
- }
-
- //左右子树都没有x,那么说明root不是路径中的节点,pop
- path.pop();
- return false;
- }
- TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
- {
- stack<TreeNode*> pPath,qPath;
- FindPath(root,p,pPath);
- FindPath(root,q,qPath);
-
- //确定长栈和短栈
- stack<TreeNode*>* longPath = &pPath;
- stack<TreeNode*>* shortPath = &qPath;
-
- if(pPath.size() < qPath.size())
- {
- swap(longPath,shortPath);
- }
-
- //让长的先走差距步
- while(longPath->size() > shortPath->size())
- {
- longPath->pop();
- }
-
- //同时走,找交点
- while(longPath->top() != shortPath->top())
- {
- longPath->pop();
- shortPath->pop();
- }
-
- return longPath->top();
- }
- };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。