2014-03-19 04:48

题目:最近公共父节点问题。

解法1:Naive算法,先对其高度,然后一层一层往上直到找到结果。

代码:

 // 4.7 Least Common Ancestor
// This solution is Naive Algorithm, may timeout on very large and skewed trees.
#include <cstdio>
#include <cstring>
using namespace std; const int MAXN = ;
// tree[x][0]: parent of node x
// tree[x][1]: left child of node x
// tree[x][2]: right child of node x
// tree[x][3]: value of node x
int tree[MAXN][];
// number of nodes
int e; void build(int a)
{
int tmp; scanf("%d", &tmp);
if(tmp)
{
tree[a][] = e;
tree[e][] = tmp;
tree[e][] = a;
++e;
// build the left subtree
build(e - );
} scanf("%d", &tmp);
if(tmp)
{
tree[a][] = e;
tree[e][] = tmp;
tree[e][] = a;
++e;
// build the right subtree
build(e - );
}
} int main()
{
int n, ni;
int i;
// the value to be queried
int m1, m2;
// the corresponding node indices of m1 and m2
int s1, s2;
int t1, t2;
int c1, c2, c; while (scanf("%d", &n) == ) {
for (ni = ; ni < n; ++ni) {
// get value for root node
e = ;
scanf("%d", &tree[][]); // root has no parent node
tree[][] = -;
build(); while (scanf("%d%d", &m1, &m2) == && (m1 && m2)) {
s1 = s2 = -;
for (i = ;i <= e; ++i) {
if (tree[i][] == m1) {
s1 = i;
// there're duplicate values
break;
}
}
for (i = ;i <= e; ++i) {
if (tree[i][] == m2) {
s2 = i;
// there're duplicate values
break;
}
} if (s1 != - && s2 != -) {
t1 = s1;
t2 = s2;
c1 = c2 = ; // c1 is the depth of t1
while (tree[t1][] != -) {
++c1;
t1 = tree[t1][];
}
// c2 is the depth of t2
while (tree[t2][] != -) {
++c2;
t2 = tree[t2][];
} // move'em to the same height level
if (c1 > c2) {
c = c1 - c2;
while(c--) {
s1 = tree[s1][];
}
} else {
c = c2 - c1;
while(c--) {
s2 = tree[s2][];
}
} while(s1 != s2)
{
s1 = tree[s1][];
s2 = tree[s2][];
}
printf("%d\n", tree[s1][]);
} else {
// At least one value is not found in the tree.
printf("Not found in the tree.\n");
}
}
}
} return ;
}

解法2:Naive算法的倍增优化。

代码:

 // 4.7 Least Common Ancestor
// O(log(n)) solution with binary decomposition.
#include <cstdio>
#include <cstring>
using namespace std; typedef struct st{
public:
int key;
st *ll;
st *rr;
st(int _key = ): key(_key), ll(NULL), rr(NULL) {}
}st; // maximal number of nodes
const int MAXN = ;
// key -> node_index mapping
int hash_key[MAXN];
// node_index -> key mapping
int key_hash[MAXN];
// depth of each node
int depth[MAXN];
// array recording ancestors
int anc[MAXN][];
// total number of nodes, index starting from 1
int nc; // recursively calculate depths of nodes
void getDepth(st *root, int dep)
{
if (root == NULL) {
return;
}
depth[hash_key[root->key]] = dep;
if (root->ll != NULL) {
getDepth(root->ll, dep + );
}
if (root->rr != NULL) {
getDepth(root->rr, dep + );
}
} // recursively construct a binary tree
void constructBinaryTree(st *&root)
{
int tmp; scanf("%d", &tmp);
if (tmp == ) {
root = NULL;
} else {
root = new st(tmp);
++nc;
if (hash_key[tmp] == ) {
hash_key[tmp] = nc;
}
key_hash[nc] = tmp;
constructBinaryTree(root->ll);
constructBinaryTree(root->rr);
}
} // recursively initialize ancestor array
void getParent(st *root)
{
if (root == NULL) {
return;
} // anc[x][0] is the direct parent of x.
if (root->ll != NULL) {
anc[hash_key[root->ll->key]][] = hash_key[root->key];
getParent(root->ll);
}
if (root->rr != NULL) {
anc[hash_key[root->rr->key]][] = hash_key[root->key];
getParent(root->rr);
}
} // calculate LCA in O(log(n)) time
int leastCommonAncestor(int x, int y)
{
int i; if (depth[x] < depth[y]) {
return leastCommonAncestor(y, x);
}
for (i = ; i >= ; --i) {
if (depth[anc[x][i]] >= depth[y]) {
x = anc[x][i];
if (depth[x] == depth[y]) {
break;
}
}
}
if (x == y) {
return x;
} for (i = ; i >= ; --i) {
if (anc[x][i] != anc[y][i]) {
// they'll finally be equal, think about the reason.
x = anc[x][i];
y = anc[y][i];
}
} // this is the direct parent of x
return anc[x][];
} st *deleteTree(st *root)
{
if (NULL == root) {
return NULL;
} if (root->ll != NULL) {
root->ll = deleteTree(root->ll);
}
if (root->rr != NULL) {
root->rr = deleteTree(root->rr);
}
delete root;
root = NULL; return NULL;
} int main()
{
int ci, cc;
int i, j;
int x, y;
st *root; while (scanf("%d", &cc) == ) {
for (ci = ; ci < cc; ++ci) {
// data initialization
memset(hash_key, , MAXN * sizeof(int));
memset(key_hash, , MAXN * sizeof(int));
memset(depth, , MAXN * sizeof(int));
memset(anc, , MAXN * * sizeof(int));
nc = ;
root = NULL; constructBinaryTree(root);
getParent(root);
getDepth(root, );
for (j = ; j < ; ++j) {
for (i = ; i <= nc; ++i) {
anc[i][j] = anc[anc[i][j - ]][j - ];
}
}
while (scanf("%d%d", &x, &y) == && (x && y)) {
if (hash_key[x] == || hash_key[y] == ) {
printf("Not found in the tree.\n");
} else {
printf("%d\n", key_hash[leastCommonAncestor(hash_key[x], hash_key[y])]);
}
} root = deleteTree(root);
}
} return ;
}

解法3:Tarjan离线算法,并查集的妙用。

代码:

 // 4.7 Least Common Ancestor
// Tarjan Offline Algorithm
#include <cstdio>
#include <cstdlib>
#include <unordered_map>
#include <unordered_set>
using namespace std; struct TreeNode {
int val;
TreeNode *left;
TreeNode *right; TreeNode(int _val = ): val(_val), left(nullptr), right(nullptr) {};
}; void constructTree(vector<TreeNode *> &nodes,
unordered_set<TreeNode *> &checked)
{
int ll, rr;
int i; for (i = ; i < (int)nodes.size(); ++i) {
checked.insert(nodes[i]);
}
for (i = ; i < (int)nodes.size(); ++i) {
scanf("%d%d", &ll, &rr);
if (ll > ) {
nodes[i]->left = nodes[ll - ];
checked.erase(nodes[ll - ]);
}
if (rr > ) {
nodes[i]->right = nodes[rr - ];
checked.erase(nodes[rr - ]);
}
}
} TreeNode *findRoot(TreeNode *node, unordered_map<TreeNode *, TreeNode *> &disjoint_set)
{
if (node != disjoint_set[node]) {
disjoint_set[node] = findRoot(disjoint_set[node], disjoint_set);
} return disjoint_set[node];
} void tarjanLCA(TreeNode *root, unordered_map<TreeNode *, TreeNode *> &disjoint_set,
unordered_map<TreeNode *, unordered_map<TreeNode *, TreeNode *> > &query,
unordered_set<TreeNode *> &checked)
{
if (root == nullptr) {
return;
} disjoint_set[root] = root;
if (root->left != nullptr) {
tarjanLCA(root->left, disjoint_set, query, checked);
disjoint_set[root->left] = root;
}
if (root->right != nullptr) {
tarjanLCA(root->right, disjoint_set, query, checked);
disjoint_set[root->right] = root;
}
checked.insert(root); if (query.find(root) == query.end()) {
return;
} unordered_map<TreeNode *, TreeNode *>::iterator it;
for (it = query[root].begin(); it != query[root].end(); ++it) {
if (it->second != nullptr) {
// already solved, skip it
continue;
}
if (checked.find(it->first) != checked.end()) {
query[root][it->first] = query[it->first][root] = findRoot(it->first, disjoint_set);
}
}
} int main()
{
int n;
int i;
int val;
vector<TreeNode *> nodes;
TreeNode *root;
unordered_map<TreeNode *, TreeNode *> disjoint_set;
unordered_map<TreeNode *, unordered_map<TreeNode *, TreeNode *> > query;
unordered_map<TreeNode *, unordered_map<TreeNode *, TreeNode *> >::iterator it1;
unordered_set<TreeNode *> checked;
unordered_map<TreeNode *, TreeNode *>::iterator it2;
int idx1, idx2; while (scanf("%d", &n) == && n > ) {
nodes.resize(n);
for (i = ; i < n; ++i) {
scanf("%d", &val);
nodes[i] = new TreeNode(val);
}
constructTree(nodes, checked);
root = *(checked.begin());
checked.clear(); while (scanf("%d%d", &idx1, &idx2) == && (idx1 >= && idx2 >= )) {
if (idx1 > idx2) {
i = idx1;
idx1 = idx2;
idx2 = i;
}
query[nodes[idx1]][nodes[idx2]] = nullptr;
query[nodes[idx2]][nodes[idx1]] = nullptr;
}
// Tarjan Offline Algorithm
tarjanLCA(root, disjoint_set, query, checked); // print the results
for (it1 = query.begin(); it1 != query.end(); ++it1) {
for (it2 = (it1->second).begin(); it2 != (it1->second).end(); ++it2) {
if (it1->first->val > it2->first->val) {
continue;
}
printf("The least common ancestor of %d and %d is %d.\n",
it1->first->val, it2->first->val, it2->second->val);
}
} // clear up
disjoint_set.clear();
checked.clear();
for (it1 = query.begin(); it1 != query.end(); ++it1) {
(it1->second).clear();
}
query.clear();
} return ;
}

《Cracking the Coding Interview》——第4章:树和图——题目7的更多相关文章

  1. Cracking the coding interview 第一章问题及解答

    Cracking the coding interview 第一章问题及解答 不管是不是要挪地方,面试题具有很好的联系代码总用,参加新工作的半年里,做的大多是探索性的工作,反而代码写得少了,不高兴,最 ...

  2. 《Cracking the Coding Interview》读书笔记

    <Cracking the Coding Interview>是适合硅谷技术面试的一本面试指南,因为题目分类清晰,风格比较靠谱,所以广受推崇. 以下是我的读书笔记,基本都是每章的课后习题解 ...

  3. Cracking the coding interview

    写在开头 最近忙于论文的开题等工作,还有阿里的实习笔试,被虐的还行,说还行是因为自己的水平或者说是自己准备的还没有达到他们所需要人才的水平,所以就想找一本面试的书<Cracking the co ...

  4. Cracking the Coding Interview(Trees and Graphs)

    Cracking the Coding Interview(Trees and Graphs) 树和图的训练平时相对很少,还是要加强训练一些树和图的基础算法.自己对树节点的设计应该不是很合理,多多少少 ...

  5. Cracking the coding interview目录及资料收集

    前言 <Cracking the coding interview>是一本被许多人极力推荐的程序员面试书籍, 详情可见:http://www.careercup.com/book. 第六版 ...

  6. Cracking the Coding Interview(Stacks and Queues)

    Cracking the Coding Interview(Stacks and Queues) 1.Describe how you could use a single array to impl ...

  7. 二刷Cracking the Coding Interview(CC150第五版)

    第18章---高度难题 1,-------另类加法.实现加法. 另类加法 参与人数:327时间限制:3秒空间限制:32768K 算法知识视频讲解 题目描述 请编写一个函数,将两个数字相加.不得使用+或 ...

  8. Cracking the Coding Interview 150题(二)

    3.栈与队列 3.1 描述如何只用一个数组来实现三个栈. 3.2 请设计一个栈,除pop与push方法,还支持min方法,可返回栈元素中的最小值.pop.push和min三个方法的时间复杂度必须为O( ...

  9. 《Cracking the Coding Interview》——第4章:树和图——题目9

    2014-03-19 05:07 题目:给定一棵二叉树T和一个值value,在T中找出所有加起来和等于value的路径.路径的起点和终点都可以是树的任意节点. 解法:我偷了个懒,直接把这棵树看成一个无 ...

  10. 《Cracking the Coding Interview》——第4章:树和图——题目8

    2014-03-19 05:04 题目:给定两棵二叉树T1和T2,判断T2是否是T1的子树.子树的定义是,以T1的某个节点(可以是T1的根)作为根节点,得到的这棵树和T2一模一样. 解法:首先可以根据 ...

随机推荐

  1. 笨办法学Python(二十七)

    习题 27: 记住逻辑关系 到此为止你已经学会了读写文件,命令行处理,以及很多 Python 数学运算功能.今天,你将要开始学习逻辑了.你要学习的不是研究院里的高深逻辑理论,只是程序员每天都用到的让程 ...

  2. 复制windows CMD命令行中的内容

    标记文本后,按"回车",或鼠标"右键"为从CMD中复制文本. 在CMD中,按鼠标"右键",为在CMD中粘贴文本.

  3. 【转载】#346 - Polymorphism

    Recall that polymorphism is one of the three core principles of object-oriented programming. Polymor ...

  4. segment and section for c++ elf

    http://blog.csdn.net/jiafu1115/article/details/12992497 写一个汇编程序保存成文本文件max.s. 汇编器读取这个文本文件转换成目标文件max.o ...

  5. 20145238-荆玉茗 《Java程序设计》第四次实验报告

    20145238<Java程序设计>第四次实验报告 实验四 Android环境搭建 实验内容 1.搭建Android环境 2.运行Android 3.修改代码,能输出学号 实验步骤 搭建A ...

  6. svn更改地址怎么办

    开发过程中有时会遇到服务器更换地址的情况,比如之前地址是 svn://www.aaa.com 后来换成了 svn://www.bbb.com 这时候怎么办呢?分客户端和服务器端2种情况处理 客户端: ...

  7. AngularJS 控制器的方法

    AngularJS 控制器也有方法(变量和函数) <!DOCTYPE html><html><head><meta http-equiv="Cont ...

  8. mac 开机白屏,卡进度条,无法进入系统

    几个月前我的老Mac又一次的坏掉了,现在想起来就记录一下,哎,话说Apple的东西吧,好用是好用,一般都不会坏,质量保证,但是如果一旦坏了,那就是大问题!(坏了第一时间就应该打电话给apple客服小姐 ...

  9. 关于使用js下载图片

    使用js进行图片下载是很常见的需求,但是解决起来却不是那么顺利. 服务器返回了一个图片地址,网上一搜基本都是用a标签的download属性,但是兼容性实在是很差.这里推荐使用blob. 上代码: va ...

  10. 交换机基础配置之三层交换机实现vlan间通信

    我们以上面的拓扑图做实验,要求为pc1,pc2,pc3配置为vlan10,pc4,pc5,pc6配置为vlan20,pc7,pc8,pc9配置为vlan30 server0和server1配置为vla ...