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. SAP CRM WebClient UI和Fiori UI混搭并存

    SAP CRM里有个功能可以创建HANA live report,消费HANA Studio里创建的模型. 最后创建好的report长这个样子: 具体创建步骤可以参考我的博客Step by Step ...

  2. Association, Composition and Aggregation in UI5, CRM, S/4HANA and C4C

    UI5 UI5使用Association和Aggregation描述控件之间的关系. Aggregation:parent和子控件在lifecycle上存在依赖关系: When a ManagedOb ...

  3. *459. Repeated Substring Pattern (O(n^2)) two pointers could be better?

    Given a non-empty string check if it can be constructed by taking a substring of it and appending mu ...

  4. Aizu The Maximum Number of Customers

    http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_5_A The Maximum Number of Customers Ide ...

  5. DFS剪枝,最大团,POJ(1419)

    题目链接:http://poj.org/problem?id=1419 题目大意:一个无向图,用黑白涂色,相邻的两个点不能图同一种颜色,求黑色的点最多有几个? 刚一看题,完全是图的m着色问题啊,我就套 ...

  6. 使用Excel管理命令输出

    效果图:(饼状图为后添加) 实现代码:

  7. 2017.9.18 HTMl学习总结----input标签的额type

    2.1.3  HTML表单标签与表单设计 (1)表单的组成:文本框(text),密码框(password),多行文本框(Multiline text box).  单选按钮框(Single - rad ...

  8. 创建 XXXXXXXX 的配置节处理程序时出错: 请求失败

    今天碰到这个错误,之前的程序在测试的时候都没有问题,同样的程序打包通过QQ传给其他人,在XP下测试也没有问题,我的Win7系统从QQ信箱下载压缩包,解压之后执行程序就会出问题,本来还是考虑自己程序是不 ...

  9. 获取页面的url

    设当前页完整地址是:http://www.jb51.net/aaa/bbb.aspx?id=5&name=kelli "http://"是协议名 "www.jb5 ...

  10. P3740 贴海报

    P3740 贴海报 很显然,这个题是让我们维护一个区间的信息 可以考虑线段树.可是这个题,正向思维可能并不可做. 所以我们考虑逆向思维. 打个比方,你是一名保洁人员.面对已经粘在墙上的,大大小小的广告 ...