剑指Offer:面试题50 树中两个节点的最低公共祖先

来源:互联网 发布:好玩的2d网络手游 编辑:程序博客网 时间:2024/05/18 03:38
看到这里的朋友,首先恭喜你们,终于把《剑指Offer》看完了。你们不容易,我也不容易,学习编程是要下一番功夫的,没有人能够随随便便成功。献给在奋斗路上的你们和我。下一个专题预告:《编程之美》/*树中两个节点的最低公共祖先:题型1:求二叉搜索树中两个结点的最低公共祖先思路:如果当前值比两个结点的值都大,那么只需要向当前节点的左子树继续向下遍历即可,直到找到介于两个结点值中间的结点。如果当前值比两个结点的值都小,那么向当前结点的右子树继续向下遍历即可。题型2:求普通树(含有指向父节点的指针)中两个结点的最低公共祖先这样的话,就可以转化为起始结点为待求节点,终点为根节点的两个链表的第一个公共结点为题。题型3:无指向父结点指针的普通树中求两个结点的最低公共祖先。用两个链表分别保存从根节点到输入的两个结点的路径,把问题转化为求两个链表的最后公共结点。比如我们得到从根节点到达F结点的路径是:A->B->D,而从根节点到达H结点的路径是:A->B->E,因此公共结点是B由于要不断的弹入弹出,因此设定一个数组和一个栈来解决输入:输入可能包含多个测试样例。对于每个测试案例,输入的第一行为一个数n(0<n<1000),代表测试样例的个数。其中每个测试样例包括两行,第一行为一个二叉树的先序遍历序列,其中左右子树若为空则用0代替,其中二叉树的结点个数node_num<10000。第二行为树中的两个结点的值m1与m2(0<m1,m2<10000)。输出:对应每个测试案例,输出给定的树中两个结点的最低公共祖先结点的值,若两个给定结点无最低公共祖先,则输出“My God”。样例输入:21 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 06 81 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 06 12样例输出:2My God题目转化为如何利用先序序列来建立二叉树,注意凡是碰到一个数字的最后用一个栈来保存父节点栈为空,且第一个节点不为叶结点,那么第一个结点为父节点一旦碰到0,表明栈中的当前节点是该0的父节点,即该父节点的左右子女均为空,此时弹出该父节点,并设置该父节点的左右子女为空。判断如果有一个结点的左右孩子均设置(不为空)了,那么弹出该节点总结:弹出栈中节点的条件1对于叶节点,即后面碰到两个0,直接弹出2对于非叶节点,当该节点的左右孩子均不空,或者当时设定一个计数器变量,进来一个增加一个计数,当有两个计数,表明左右孩子均建立了,此时可以弹出该结点总过程:1寻找路径2获取两条路径上最后一个公共的节点*//*关键:1 题型1:求二叉搜索树中两个结点的最低公共祖先思路:如果当前值比两个结点的值都大,那么只需要向当前节点的左子树继续向下遍历即可,直到找到介于两个结点值中间的结点。如果当前值比两个结点的值都小,那么向当前结点的右子树继续向下遍历即可。题型2:求普通树(含有指向父节点的指针)中两个结点的最低公共祖先这样的话,就可以转化为起始结点为待求节点,终点为根节点的两个链表的第一个公共结点为题。题型3:无指向父结点指针的普通树中求两个结点的最低公共祖先。用两个链表分别保存从根节点到输入的两个结点的路径,把问题转化为求两个链表的最后公共结点。比如我们得到从根节点到达F结点的路径是:A->B->D,而从根节点到达H结点的路径是:A->B->E,因此公共结点是B2   pHead = createNode();  //pHead = &nodeArr[iPos+1];  pHead->_iVal = pArr[iPos];  iPos++;  pHead->_left = buildTree(pArr,iLen,iPos);//用先序序列递归来建立二叉树  pHead->_right = buildTree(pArr,iLen,iPos);3  if(pArr[iPos] == 0)//叶子节点标记 {  iPos++;//注意,这里碰到0之后一定要累加,否则陷入死循环中  return NULL; }4  if(!pRoot || !pFind)//如果为空,直接返回false,并且不加入这个节点 {  return false; } if(pFind == pRoot)//如果根节点就是要找的节点,就直接返回 {  return true; } listPath.push_back(pRoot);5  if(!isFind)//注意,如果始终没有找到,就退回到上一层 {  listPath.pop_back(); }6   while(EOF != scanf("%d",&iDataArr[iCnt++]))//以换行作为分隔,如何判定输入结束   {    ch = getchar();    if(ch == '\n')//用gtechar() != '\n' 来判断一个数组是否结束输入*/#include <stdio.h>#include <iostream>#include <string.h>#include <list>#include <string>using namespace std;const int MAXSIZE = 1e4 + 1;const int INF = 0x7fffffff;typedef struct Node{ int _iVal; Node* _left; Node* _right;}Node;Node nodeArr[MAXSIZE];int _iIndex;Node* createNode(){ ++_iIndex; nodeArr[_iIndex]._left = nodeArr[_iIndex]._right = NULL; nodeArr[_iIndex]._iVal = INF; return &nodeArr[_iIndex];}Node* buildTree(int* pArr,int iLen,int& iPos){ if(!pArr || iLen < 0 )//鲁棒性 {  return NULL; } if(iPos == iLen)//递归出口 {  return NULL; } Node* pHead; if(pArr[iPos] == 0)//叶子节点标记 {  iPos++;//注意,这里碰到0之后一定要累加,否则陷入死循环中  return NULL; } else {  pHead = createNode();  //pHead = &nodeArr[iPos+1];  pHead->_iVal = pArr[iPos];  iPos++;  pHead->_left = buildTree(pArr,iLen,iPos);//用先序序列递归来建立二叉树  pHead->_right = buildTree(pArr,iLen,iPos); } return pHead;}void frontVisit(Node* pHead){ if(!pHead)//递归出口 {  return; } printf("%d ",pHead->_iVal); frontVisit(pHead->_left); frontVisit(pHead->_right);}bool getPath(Node* pRoot,Node* pFind,list<Node*>& listPath){ if(!pRoot || !pFind)//如果为空,直接返回false,并且不加入这个节点 {  return false; } if(pFind == pRoot)//如果根节点就是要找的节点,就直接返回 {  return true; } listPath.push_back(pRoot); bool isFind = false; if(!isFind) {  isFind = getPath(pRoot->_left,pFind,listPath); } if(!isFind) {  isFind = getPath(pRoot->_right,pFind,listPath); } if(!isFind)//注意,如果始终没有找到,就退回到上一层 {  listPath.pop_back(); } return isFind;}Node* getLastCommonNode(list<Node*>& listPath1,list<Node*>& listPath2){ list<Node*>::iterator it1 = listPath1.begin(); list<Node*>::iterator it2 = listPath2.begin(); Node* pLast = NULL; while(it1 != listPath1.end() && it2 != listPath2.end()) {  if(*it1 == *it2)  {   pLast = *it1;  }  it1++;  it2++; } return pLast;} //注意,还需要建立节点值与节点下标的映射,不然的话,在创建的时候,直接返回第节点值对应的节点地址Node* findNode(Node* pHead,int iVal){ if(!pHead || iVal <= 0 || iVal >= MAXSIZE) {  return NULL; } else {  Node* pNode;  if(pHead->_iVal != iVal)  {   pNode = findNode(pHead->_left,iVal);   if(pNode)//如果已经找到,直接返回   {    return pNode;   }   pNode = findNode(pHead->_right,iVal);   if(pNode)   {    return pNode;   }  }  else  {   return pHead;  } }}void process(){ int n; while(EOF != scanf("%d",&n)) {  while(n--)  {   memset(nodeArr,NULL,sizeof(nodeArr));   _iIndex = 0;   int iDataArr[MAXSIZE];   int iCnt = 0;   char ch;   while(EOF != scanf("%d",&iDataArr[iCnt++]))//以换行作为分隔,如何判定输入结束   {    ch = getchar();    if(ch == '\n')//用gtechar() != '\n' 来判断一个数组是否结束输入    {     break;    }   }   int iPos = 0;   Node* pHead = buildTree(iDataArr,iCnt,iPos);//根据先序序列,调用递归函数来建立二叉树   //frontVisit(pHead);   //printf("\n");   int m1,m2;   scanf("%d %d",&m1,&m2);   Node* pNode1 = findNode(pHead,m1);   if(!pNode1)   {    printf("My God\n");    continue;   }   Node* pNode2 = findNode(pHead,m2);   if(!pNode2)   {    printf("My God\n");    continue;   }   list<Node*> listPath1;   list<Node*> listPath2;   if(getPath(pHead,pNode1,listPath1) && getPath(pHead,pNode2,listPath2))//如果找到路径1,2,4与1,2,5(不包含本身节点)   {    Node* pAncestor = getLastCommonNode(listPath1,listPath2);    printf("%d\n",pAncestor->_iVal);   }   else   {    printf("My God\n");    continue;       }  } }}int main(int argc,char* argv[]){ process(); getchar(); return 0;}//需要一个判断是左还是右的标记//void buildTree(Node** pHead,int* pArr,int iLen)//{// bool isLeft = true;// bool isVisitLeft = false;// bool isVisitRight = false;// stack<Node*> stackNode;// int i = 0;// while(i < iLen)// {//  if(pArr[i]== 0)//如果碰到了0,就再判断下一个是否是0,如果两个都是0//  {//   if(isLeft)//左边的0//   {//    isLeft = false;//   }//   else//如果碰到的是右边的0,弹出栈中的当前节点//   {//    if(stackNode.size() > 0)//    {//     stackNode.pop();//    }//   }//   i++;//  }//  else//如果碰到的不是0//  {//   if(!i)//   {//    Node* pCurNode = createNode();//    pCurNode->_iVal = pArr[i];//    Node* pParentNode = stackNode.top();//    if(isLeft)//如果碰到的是左节点,那么设定栈中的父节点指向该节点//    {////     pParentNode->_left = pCurNode;//     isLeft = false;//    }//    else//如果碰到的是右结点//    {//     pParentNode->_right = pCurNode;//     isLeft = true;//    }//   }//   else//如果是根节点//   {//    (*pHead)->_iVal = pArr[i];//    stackNode.push(*pHead);//   }//  }//  }// }//}


 

0 0
原创粉丝点击