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. JSON:使用json_encode函数解析结果为Null

    1.首先,数据库中的json数据是这样的 2.仓鼠使用json_encode()函数进行解析json数据时,显示了一个NULL: 3.这时候,我们需要使用,表示在解析json之前,该json是有语法错 ...

  2. GNU Nano编辑器

    ^表示 control建 ^X 退出 nano ^O 保存文件 ^R 插入其他文件内容至光标位置 ^W 查找字符串 ^Y 跳至前一屏 ^V 跳至后一屏 ^K 剪切光标所在行并保存到剪贴板,或剪切选中内 ...

  3. A. Kyoya and Colored Balls_排列组合,组合数

    Codeforces Round #309 (Div. 1) A. Kyoya and Colored Balls time limit per test 2 seconds memory limit ...

  4. CentOS系统中使用iptables设置端口转发

    echo 1 > /proc/sys/net/ipv4/ip_forward 首先应该做的是/etc/sysctl.conf配置文件的 net.ipv4.ip_forward = 1 默认是0  ...

  5. 安裝 PHP 時出現undefined reference to `libiconv_open’ 之類的錯誤訊息

    在安裝 PHP 到系統中時要是發生「undefined reference to `libiconv_open'」之類的錯誤訊息,那表示在「./configure 」沒抓好一些環境變數值.錯誤發生點在 ...

  6. MVAPICH

    from:https://developer.nvidia.com/mvapich MVAPICH2 is an open source implementation of Message Passi ...

  7. Login用户登录(Python实现)

    username_fault = "isuperSun" #程序存储用户名和密码 password_fault = " counts = 0 while counts&l ...

  8. Oracle SCN与时间的相互转换

    1.SCN转换成时间 select scn_to_timestamp(current_scn) from v$database; 2.时间转换成SCN select timestamp_to_scn( ...

  9. Excle 常用函数

    1. 查找函数VLOOKUP 使用示例: =VLOOKUP(A1,$C$1:$D$19,2,0) 表示以A1单元格为基准,匹配C1开始到D19的范围数据,在公式行显示D单元格文本,也就是匹配范围的第二 ...

  10. Hibernate 异常总结

    异常一 异常一 异常描述: Sax解析异常:cvc-复杂的类型,发现了以元素maping开头的无效内容,应该是以 ‘{“http://www.hibernate.org/xsd/orm/cfg“:pr ...