【面试题050】树中两个结点的最低公共祖先
题目:
树中两个节点的最低公共祖先。
思路一:
输入两个树节点,求他们的最低公共祖先,
——如果是二叉树,而且是二叉搜索树,那么是可以找到公共节点的。
二叉搜索树都是排序过的,位于左子树的节点都比父节点小,而位于右子树上面的节点都比父节点大。
- 如果当前节点的值比两个结点 的值都大,那么最低的共同的父节点一定是在当前节点的左子树中,于是下一步遍历当前节点的左子节点。
- 如果当前节点的值比两个结点的值都小,那么最低的共同的父节点一定是在当前节点的右子树中,于是下一步遍历当前节点的右子节点。
- 这样从上到下,找到的第一个在两个输入结点的值之间的节点,就是最低的公共祖先。
思路二:
如果这棵树不是二叉搜索树,甚至连二叉树都不是,而只是普通的树。
——如果有指向父节点的指针,那么这个题目转换成了求,两个双向链表的第一个公共结点的问题。
思路三:
这棵树是普通的树,而且这个树中的结点没有指向父节点的指针。
——遍历这个树,看以这个节点为根的子树是否包含这两个节点,如果包含,判断这个节点的子节点是否包含,
——知道子节点都不包含而这个当前的节点包含,那么这个节点就是最低的公共祖先。
ps.这里存在大量的重复遍历,效率不高。
思路三:
这棵树是普通的树,而且这个树中的结点没有指向父节点的指针。
——用两个链表分别保存从根节点到输入的两个结点的路径,然后把问题转换成两个链表的最后公共节点。
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
#include <iostream>
#include <list> #include <vector> #include "Tree.h" using namespace std; bool GetNodePath(TreeNode *pRoot, TreeNode *pNode, list<TreeNode *> &path) { if (pRoot == pNode) { return true; } path.push_back(pRoot); bool found = false; vector<TreeNode *>::iterator i = pRoot->m_vChildren.begin(); while (!found && i < pRoot->m_vChildren.end()) { found = GetNodePath(*i, pNode, path); ++i; } if (!found) { path.pop_back(); } return found; } TreeNode *GetLastCommonNode ( const list<TreeNode *> &path1, const list<TreeNode *> &path2 ) { list<TreeNode *>::const_iterator iterator1 = path1.begin(); list<TreeNode *>::const_iterator iterator2 = path2.begin(); TreeNode *pLast = NULL; while (iterator1 != path1.end() && iterator2 != path2.end()) { if (*iterator1 == *iterator2) { pLast = *iterator1; } iterator1++; iterator2++; } return pLast; } TreeNode *GetLastCommonParent(TreeNode *pRoot, TreeNode *pNode1, TreeNode *pNode2) { if (pRoot == NULL || pNode1 == NULL || pNode2 == NULL) { return NULL; } list<TreeNode *> path1; GetNodePath(pRoot, pNode1, path1); list<TreeNode *> path2; GetNodePath(pRoot, pNode2, path2); return GetLastCommonNode(path1, path2); } // 形状普通的树 // 1 // / \ // 2 3 // / \ // 4 5 // / \ / | \ // 6 7 8 9 10 int main() { TreeNode *pNode1 = CreateTreeNode( 1); TreeNode *pNode2 = CreateTreeNode( 2); TreeNode *pNode3 = CreateTreeNode( 3); TreeNode *pNode4 = CreateTreeNode( 4); TreeNode *pNode5 = CreateTreeNode( 5); TreeNode *pNode6 = CreateTreeNode( 6); TreeNode *pNode7 = CreateTreeNode( 7); TreeNode *pNode8 = CreateTreeNode( 8); TreeNode *pNode9 = CreateTreeNode( 9); TreeNode *pNode10 = CreateTreeNode( 10); ConnectTreeNodes(pNode1, pNode2); ConnectTreeNodes(pNode1, pNode3); ConnectTreeNodes(pNode2, pNode4); ConnectTreeNodes(pNode2, pNode5); ConnectTreeNodes(pNode4, pNode6); ConnectTreeNodes(pNode4, pNode7); ConnectTreeNodes(pNode5, pNode8); ConnectTreeNodes(pNode5, pNode9); ConnectTreeNodes(pNode5, pNode10); TreeNode *pRoot = pNode1; TreeNode *Node1 = pNode6; TreeNode *Node2 = pNode8; TreeNode *pResult = GetLastCommonParent(pRoot, Node1, Node2); cout << pResult->m_nValue << endl; //输出2 return 0; } |
Tree.h:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#ifndef _TREE_H_
#define _TREE_H_ #include <vector> struct TreeNode { int m_nValue; std::vector<TreeNode *> m_vChildren; }; TreeNode *CreateTreeNode( int value); void ConnectTreeNodes( TreeNode *pParent, TreeNode *pChild); void PrintTreeNode(TreeNode *pNode); void PrintTree(TreeNode *pRoot); void DestroyTree(TreeNode *pRoot); #endif //_TREE_H_ |
Tree.cpp:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
#include
"Tree.h"
TreeNode *CreateTreeNode( int value) { TreeNode *pNode = new TreeNode(); pNode->m_nValue = value; return pNode; } void ConnectTreeNodes(TreeNode *pParent, TreeNode *pChild) { if(pParent != NULL) { pParent->m_vChildren.push_back(pChild); } } void PrintTreeNode(TreeNode *pNode) { if(pNode != NULL) { printf( "value of this node is: %d.\n", pNode->m_nValue); printf( "its children is as the following:\n"); std::vector<TreeNode *>::iterator i = pNode->m_vChildren.begin(); while(i < pNode->m_vChildren.end()) { if(*i != NULL) printf( "%d\t", (*i)->m_nValue); } printf( "\n"); } else { printf( "this node is null.\n"); } printf( "\n"); } void PrintTree(TreeNode *pRoot) { PrintTreeNode(pRoot); if(pRoot != NULL) { std::vector<TreeNode *>::iterator i = pRoot->m_vChildren.begin(); while(i < pRoot->m_vChildren.end()) { PrintTree(*i); ++i; } } } void DestroyTree(TreeNode *pRoot) { if(pRoot != NULL) { std::vector<TreeNode *>::iterator i = pRoot->m_vChildren.begin(); while(i < pRoot->m_vChildren.end()) { DestroyTree(*i); ++i; } delete pRoot; } } |