算法:寻找树中两个结点的最低公共祖先

来源:互联网 发布:大数据分析师工资 编辑:程序博客网 时间:2024/05/17 02:19
题型1.若树为二叉搜索树,则从根节点开始遍历,第一个在两个输入结点值之间的结点即为最低公共祖先题型2.若为普通树,如果结点中有指向父结点的指针,那么该问题就变成了求两个链表的第一个公共结点问题题型3.若为普通树,且结点中没有指向父结点的指针*//************************************************************************///针对题型3的三种解法//解法一:需要辅助空间(需要两个链表分别存储从根节点到两个输入结点之间的路径,转而求两个链表的第一个公共结点问题bool GetListofNode(TreeNode* head, TreeNode* node, vector<TreeNode*> &vecNode){bool bFind=false;if (head==NULL)return false;vecNode.push_back(head);if (head==node)return true;if (head->left)bFind=GetListofNode(head->left,node,vecNode);if (!bFind){if (head->right){bFind = GetListofNode(head->right,node,vecNode);}}if (!bFind)vecNode.pop_back();return bFind;}TreeNode* FindFirstCommonnode(TreeNode* Head, TreeNode* node1, TreeNode* node2){if (Head==NULL || node1==NULL || node2==NULL)   return NULL;TreeNode* pret = NULL;vector<TreeNode*> vecNode1, vecNode2;if(GetListofNode(Head,node1,vecNode1) && GetListofNode(Head,node2,vecNode2))//获得从根节点开始到两个输入结点的路径{vector<TreeNode*>::iterator it1 = vecNode1.begin();vector<TreeNode*>::iterator it2 = vecNode2.begin();while(it1!=vecNode1.end() && it2!=vecNode2.end()){if (*it1==*it2)    pret=*it1;elsereturn pret;//不相等,则返回it1++;it2++;}}return pret;}//解法二:不利用辅助空间//设两个结点为p,q //情况1:如果p,q在根节点的两侧,那么直接返回根节点(牛逼,没有想到利用根节点两侧结点的共同祖先就是根节点)//情况2:如果p,q中有一个为根节点,则直接返回根节点(考虑到p,q在一条链上的情况,很关键) //由于从根节点一直向下做上述判断,就一定会进入情况1或情况2,从根节点向下,对每个结点进行上述处理,时间复杂度为O(N)bool isChildNode(TreeNode* head , TreeNode* node)  {  if(NULL == node)  {  return false;  }  //如果根节点都为空了,说明当前结点不是根节点的子孙结点  if(NULL == head)  {  return false;  }  if(node == head)  {  return true;  }  else  {  //递归处理,注意如果一个结点都不在根节点的左右孩子结点中,那么这个结点必定不是根节点的子孙结点,这里用"||"  return isChildNode(head->left , node) || isChildNode(head->right , node);  }  }  TreeNode* findCommonAncestor(TreeNode* head, TreeNode* node1 , TreeNode* node2)  {  //鲁棒性  if(NULL == head || NULL == node1 || NULL == node2)  {  return NULL;  }  //1如果两个结点中有一个为根节点,直接返回该结点即可  if(node1 == head)  {  return node1;  }  if(node2 == head)  {  return node2;  }  //2如果两个结点分别位于根节点的两侧,则直接返回根节点  bool isNode1OnLeft = isChildNode(head->left , node1);  bool isNode2OnLeft = isChildNode(head->left , node2);  if(isNode1OnLeft != isNode2OnLeft)  {  return head;  }  //3如果两个结点位于根节点同一侧,则令根节点为其同一侧子树的根节点  else  {  //如果都在根节点左侧  if(isNode1OnLeft)  {  return findCommonAncestor(head->left, node1 , node2);  }  else  {  return findCommonAncestor(head->right, node1 , node2);  }  }  }  //解法三:从上往下遍历,最后一个同时包含两个结点的结点即为最低公共结点

原创粉丝点击