★ACM基础知识|求解二叉树中两个节点的最近公共祖先(LCA)

/************************************************************************/ /* 非递归的方法下面是一个简单的复杂度为 O(n) 的算法,解决LCA问题1) 找到从根到n1的路径,并存储在一个向量或数组中。 2)找到从根到n2的路径,并存储在一个向量或数组中。 3) 遍历这两条路径,直到遇到一个不同的节点,则前面的那个即为最低公共祖先.*/ /************************************************************************///二叉树节点 struct Node { int key; Node *left, *right; }; //找到从root到 节点值为key的路径,存储在path中。没有的话返回-1 bool findpath(Node * root,vector &path,int key) { if(root == NULL) return false; path.push_back(root->key); if(root->key == key) return true; //左子树或右子树 是否找到,找到的话当前节点就在路径中了 bool find =( findpath(root->left, path, key) || findpath(root->right,path ,key) ); if(find) return true; //该节点下未找到就弹出 path.pop_back(); return false; }int findLCA(Node * root,int key1,int key2) { vector path1,path2; bool find1 = findpath(root, path1, key1); bool find2 = findpath(root, path2, key2); if(find1 && find2) { int ans ; for(int i=0; i < path1.size(); i++) { if(path1[i] != path2[i]) { break; } else { ans = path1[i]; } } return ans; } return -1; }/************************************************************************/ /* 递归求解方法从root开始遍历,如果n1和n2中的任一个和root匹配,那么root就是LCA。 如果都不匹配,则分别递归左、右子树, 如果有一个 key(n1或n2)出现在左子树,并且另一个key(n1或n2)出现在右子树,则root就是LCA. 如果两个key都出现在左子树,则说明LCA在左子树中,否则在右子树。 */ /************************************************************************/struct Node { struct Node *left, *right; int key; }; // 返回n1和n2的 LCA的指针 // 假设n1和n2都出现在树中 struct Node *findLCA(struct Node* root, int n1, int n2) { if (root == NULL) return NULL; // 只要n1 或 n2 的任一个匹配即可 //(注意:如果 一个节点是另一个祖先,则返回的是祖先节点。因为递归是要返回到祖先的 ) if (root->key == n1 || root->key == n2) return root; // 分别在左右子树查找 Node *left_lca= findLCA(root->left, n1, n2); Node *right_lca = findLCA(root->right, n1, n2); // 如果都返回非空指针 Non-NULL, 则说明两个节点分别出现了在两个子树中,则当前节点肯定为LCA if (left_lca && right_lca)return root; // 如果一个为空,在说明LCA在另一个子树 return (left_lca != NULL)? left_lca: right_lca; }


    推荐阅读