给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。
最近公共祖先是两个节点的公共的祖先节点且具有最大深度。
假设给出的两个节点都在树中存在。
dfs递归写法
查找两个node的最近公共祖先,分三种情况:
- 如果两个node在root的两边,那么最近公共祖先就是root。
- 如果两个node在root的左边,那么把root的左子树作为root,再递归。
- 如果两个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 }