剑指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
- [剑指offer][面试题50]树中两个节点的最低公共祖先
- 剑指Offer:面试题50 树中两个节点的最低公共祖先
- 剑指offer 面试题50—树中两个节点的最低公共祖先
- 剑指offer 面试题50 树中两个节点的最低公共祖先
- 《剑指offer》面试题50 树中两个结点的最低公共祖先
- 《剑指Offer》学习笔记--面试题50:树中两个结点的最低公共祖先
- 【剑指offer】 面试题50: 树中两个结点的最低公共祖先
- 【剑指Offer学习】【面试题50:树中两个结点的最低公共祖先】
- 剑指offer之面试题50树中两个结点的最低公共祖先
- 剑指offer--面试题50:树中两个结点的最低公共祖先
- 剑指offer——面试题50:树中两个结点的最低公共祖先
- 剑指offer-面试题50-树中两个结点的最低公共祖先
- 剑指offer 面试题50 树中两个结点的最低公共祖先
- 剑指offer-树中两个节点的最低公共祖先
- 剑指offer-树中两个节点的最低公共祖先
- 树中两个节点的最低公共祖先(剑指offer)
- 面试题50 树中两个节点的最低公共祖先LCA(Lowest Common Ancestor )
- 面试题50:二叉树中两个节点的最低公共祖先
- 剑指Offer:面试题49 把字符串转换成整数
- IBM高层接受采访时透露更多与苹果合作细节
- 检验文件夹路径是否合法-MFC
- Effective C++ 33 避免遮掩继承而来的名称
- 最好的5个Android ORM框架
- 剑指Offer:面试题50 树中两个节点的最低公共祖先
- lua学习1
- Codeigniter 利用加密Key(密钥)的对象注入漏洞
- CentOS 5.5 Install ntfs-3g
- 欧拉回路模版
- 常用CSS命名规则
- Android关于PagerAdapter的使用方法的总结
- 阿里云linux云主机配置
- 程序设计基础——编程语言概述