最近公共祖先 LCA 递归非递归

给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。
最近公共祖先是两个节点的公共的祖先节点且具有最大深度。
假设给出的两个节点都在树中存在。

dfs递归写法

查找两个node的最近公共祖先,分三种情况:

  1. 如果两个node在root的两边,那么最近公共祖先就是root。
  2. 如果两个node在root的左边,那么把root的左子树作为root,再递归。
  3. 如果两个node在root的右边,那么把root的右子树作为root,再递归。

深度优先遍历二叉树,一旦找到了两个节点其中的一个,就将这个几点返回给上一层,上一层节点通过判断其左右子树中是否恰好包含n1和n2两个节点,如果找到,对应的上一层节点肯定是所求的LCA;若果不是,将包括两个节点中任意一个的较低的节点返回给上一层,否则返回NULL。

 1 /**
 2  * Definition of TreeNode:
 3  * class TreeNode {
 4  * public:
 5  *     int val;
 6  *     TreeNode *left, *right;
 7  *     TreeNode(int val) {
 8  *         this->val = val;
 9  *         this->left = this->right = NULL;
10  *     }
11  * }
12  */
13 
14 
15 class Solution {
16 public:
17     /*
18      * @param root: The root of the binary search tree.
19      * @param A: A TreeNode in a Binary.
20      * @param B: A TreeNode in a Binary.
21      * @return: Return the least common ancestor(LCA) of the two nodes.
22      */
23     TreeNode * lowestCommonAncestor(TreeNode * root, TreeNode * A, TreeNode * B) {
24         // write your code here
25         //如果当前节点为空,或者与目标节点中的一个相同,则返回该节点
26         if(root == NULL)    return NULL;
27         if(root==A || root==B)  return root;
28         
29         //递归寻找A B在左右子树的位置
30         TreeNode* left = lowestCommonAncestor(root->left,A,B);
31         TreeNode* right = lowestCommonAncestor(root->right,A,B);
32         
33         //如果A B分别位于root的两侧,则root是他们的LCA,否则是左子树或者右子树
34         if(left&&right) return root;
35         
36         return left?left:right;
37         
38         
39     }
40 };

非递归:

后序遍历非递归

 1 TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
 2     if (root == nullptr)
 3         return root;
 4     stack<TreeNode*> s;
 5     vector<TreeNode*> vec; // p和q的公共祖先
 6     bool tag1 = false; // true:找到p
 7     bool tag2 = false; // true:找到q
 8     s.push(root);
 9     TreeNode* lastRoot = root;
10     while (!s.empty()) // lastRoot(区分从左/右孩子返回)
11     {
12         root = s.top();
13         if (root == p) {
14             if(tag1 == false && tag2 == false)
15                 vec.push_back(root);
16             tag1 = true;
17         }
18         else if (root == q) {
19             if (tag2 == false && tag1 == false)
20                 vec.push_back(root);
21             tag2 = true;
22         }
23         if (!tag1 && !tag2)
24             vec.push_back(root); // 公共祖先入vector
25         // 找到p,q并且root在公共祖先数组中
26         if (tag1 && tag2 && find(vec.begin(), vec.end(), root) != vec.end())
27             return root;
28         // root的孩子节点还没访问
29         if (lastRoot != root->right)
30         {
31             if (lastRoot != root->left) {
32                 if (root->left != nullptr) {
33                     s.push(root->left);
34                     continue;
35                 }
36             }
37             if (root->right != nullptr) {
38                 s.push(root->right);
39                 continue;
40             }
41         }
42         // 孩子节点访问完,弹栈向上回溯
43         lastRoot = root;
44         s.pop();
45     }
46     return nullptr;
47 }

 

转载于:https://www.cnblogs.com/demian/p/11031113.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值