剑指Offer

剑指Offer - 九度1509 - 树中两个结点的最低公共祖先
2014-02-07 01:04
题目描述:

给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。

输入:

输入可能包含多个测试样例。
对于每个测试案例,输入的第一行为一个数n(0<n<1000),代表测试样例的个数。
其中每个测试样例包括两行,第一行为一个二叉树的先序遍历序列,其中左右子树若为空则用0代替,其中二叉树的结点个数node_num<10000。
第二行为树中的两个结点的值m1与m2(0<m1,m2<10000)。

输出:

对应每个测试案例,
输出给定的树中两个结点的最低公共祖先结点的值,若两个给定结点无最低公共祖先,则输出“My God”。

样例输入:
2
1 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 0
6 8
1 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 0
6 12
样例输出:
2
My God
题意分析:
  这道题要求将二叉搜索树转换成双向链表,我的思路是进行后序遍历。先将左右子树搞定以后,再处理根节点。
  求最近公共父节点的常用方法,有Tarjan离线算法,在线倍增法,Naive算法。
  目前我只写了Naive算法和在线倍增法的代码,结果提交后发现Naive算法通过,倍增法始终Wrong Answer。
  检查代码许久,开始怀疑数据有问题,于是在两处设置了死循环的测试代码,提交结果中果然有两处问题:
    1. 查询的节点值可能为0,也就是代表NULL的0。这个我倒是可以处理好。
    2. 二叉树中的节点值是可能有重复的,比如值为5的节点可以有很多个,那么输入5的话让我找哪个?推测倍增法出错和这个有关。
  由于这题数据有问题,所以没有继续写Tarjan版本的欲望了,很可能也AC不掉。我会在Leetcode中的对应题目附上三种方法的讲解,此处就不做详述了。
  Naive算法时间复杂度O(h),其中h为二叉树的高度,平均为O(log(n)),对于斜树来说则是O(n)。
  倍增法则用O(n * log(n))空间复杂度和O(n * log(n))预处理时间,来获取O(log(n))的稳定查询复杂度。
  1 // 690809    zhuli19901106    1509    Accepted    点击此处查看所有case的执行结果    1176KB    6753B    120MS
  2 // 201402050235
  3 // This solution is Naive Algorithm, may fail on very large skewed tree.
  4 // If you optimize it with ancestor array to achieve O(log(n)) time, you'll get WA.
  5 // Because the test data of this problem have some illegal input.
  6 #include <cstdio>
  7 #include <cstring>
  8 using namespace std;
  9 
 10 const int MAXN = 10005;
 11 // tree[x][0]: parent of node x
 12 // tree[x][1]: left child of node x
 13 // tree[x][2]: right child of node x
 14 // tree[x][3]: value of node x
 15 int tree[MAXN][4];
 16 // number of nodes
 17 int e;
 18 
 19 void build(int a)
 20 {
 21     int tmp;
 22 
 23     scanf("%d", &tmp);
 24     if(tmp)
 25     {
 26         tree[a][1] = e;
 27         tree[e][3] = tmp;
 28         tree[e][0] = a;
 29         ++e;
 30         // build the left subtree
 31         build(e - 1);
 32     }
 33 
 34     scanf("%d", &tmp);
 35     if(tmp)
 36     {
 37         tree[a][2] = e;
 38         tree[e][3] = tmp;
 39         tree[e][0] = a;
 40         ++e;
 41         // build the right subtree
 42         build(e - 1);
 43     }
 44 }
 45 int main()
 46 {
 47     int n, ni;
 48     int i;
 49     // the value to be queried
 50     int m1, m2;
 51     // the corresponding node indices of m1 and m2
 52     int s1, s2;
 53     int t1, t2;
 54     int c1, c2, c;
 55 
 56     while (scanf("%d", &n)  == 1) {
 57         for (ni = 0; ni < n; ++ni) {
 58             // get value for root node
 59             e = 1;
 60             scanf("%d", &tree[0][3]);
 61 
 62             // root has no parent node
 63             tree[0][0] = -1;
 64             build(0);
 65 
 66             scanf("%d%d", &m1, &m2);
 67             s1 = s2 = -1;
 68             for (i = 0;i <= e; ++i) {
 69                 if (tree[i][3] == m1) {
 70                     s1 = i;
 71                     // there're duplicate values
 72                     break;
 73                 }
 74             }
 75             for (i = 0;i <= e; ++i) {
 76                 if (tree[i][3] == m2) {
 77                     s2 = i;
 78                     // there're duplicate values
 79                     break;
 80                 }
 81             }
 82 
 83             if (s1 != -1 && s2 != -1) {
 84                 t1 = s1;
 85                 t2 = s2;
 86                 c1 = c2 = 0;
 87 
 88                 // c1 is the depth of t1
 89                 while (tree[t1][0] != -1) {
 90                     ++c1;
 91                     t1 = tree[t1][0];
 92                 }
 93                 // c2 is the depth of t2
 94                 while (tree[t2][0] != -1) {
 95                     ++c2;
 96                     t2 = tree[t2][0];
 97                 }
 98                 // move'em to the same height level
 99                 if (c1 > c2) {
100                     c = c1 - c2;
101                     while(c--) {
102                         s1 = tree[s1][0];
103                     }
104                 }
105                 if (c2 > c1) {
106                     c = c2 - c1;
107                     while(c--) {
108                         s2 = tree[s2][0];
109                     }
110                 }
111                 while(s1 != s2)
112                 {
113                     s1 = tree[s1][0];
114                     s2 = tree[s2][0];
115                 }
116                 printf("%d
", tree[s1][3]);
117             } else {
118                 // At least one value is not found in the tree.
119                 printf("My God
");
120             }
121         }
122     }
123 
124     return 0;
125 }
126 
127 /*
128 // This here is my last version of code, got some strange WAs.
129 // I doubt if the test data is really legal as described.
130 // 1. m1 and m2 may be 0
131 // 2. some tree nodes may have same values, making things ambiguous.
132 // I'll prove my suspicion.
133 #include <cstdio>
134 #include <cstring>
135 using namespace std;
136 
137 typedef struct st{
138 public:
139     int key;
140     st *ll;
141     st *rr;
142     st(int _key = 0): key(_key), ll(NULL), rr(NULL) {}
143 }st;
144 
145 // maximal number of nodes
146 const int MAXN = 10005;
147 // key -> node_index mapping
148 int hash_key[MAXN];
149 // node_index -> key mapping
150 int key_hash[MAXN];
151 // depth of each node
152 int depth[MAXN];
153 // array recording ancestors
154 int anc[MAXN][16];
155 // total number of nodes, index starting from 1
156 int nc;
157 
158 // recursively calculate depths of nodes
159 void getDepth(st *root, int dep)
160 {
161     if (root == NULL) {
162         return;
163     }
164     depth[hash_key[root->key]] = dep;
165     if (root->ll != NULL) {
166         getDepth(root->ll, dep + 1);
167     }
168     if (root->rr != NULL) {
169         getDepth(root->rr, dep + 1);
170     }
171 }
172 
173 // recursively construct a binary tree
174 void constructBinaryTree(st *&root)
175 {
176     int tmp;
177 
178     scanf("%d", &tmp);
179     if (tmp == 0) {
180         root = NULL;
181     } else {
182         root = new st(tmp);
183         ++nc;
184         if (hash_key[tmp] == 0) {
185             hash_key[tmp] = nc;
186         }
187         key_hash[nc] = tmp;
188         constructBinaryTree(root->ll);
189         constructBinaryTree(root->rr);
190     }
191 }
192 
193 // recursively initialize ancestor array
194 void getParent(st *root)
195 {
196     if (root == NULL) {
197         return;
198     }
199 
200     // anc[x][0] is the direct parent of x.
201     if (root->ll != NULL) {
202         anc[hash_key[root->ll->key]][0] = hash_key[root->key];
203         getParent(root->ll);
204     }
205     if (root->rr != NULL) {
206         anc[hash_key[root->rr->key]][0] = hash_key[root->key];
207         getParent(root->rr);
208     }
209 }
210 
211 // calculate LCA in O(log(n)) time
212 int leastCommonAncestor(int x, int y)
213 {
214     int i;
215 
216     if (depth[x] < depth[y]) {
217         return leastCommonAncestor(y, x);
218     }
219     for (i = 15; i >= 0; --i) {
220         if (depth[anc[x][i]] >= depth[y]) {
221             x = anc[x][i];
222             if (depth[x] == depth[y]) {
223                 break;
224             }
225         }
226     }
227     if (x == y) {
228         return x;
229     }
230 
231     for (i = 15; i >= 0; --i) {
232         if (anc[x][i] != anc[y][i]) {
233             // they'll finally be equal, think about the reason.
234             x = anc[x][i];
235             y = anc[y][i];
236         }
237     }
238 
239     // this is the direct parent of x
240     return anc[x][0];
241 }
242 
243 st *deleteTree(st *root)
244 {
245     if (NULL == root) {
246         return NULL;
247     }
248 
249     if (root->ll != NULL) {
250         root->ll = deleteTree(root->ll);
251     }
252     if (root->rr != NULL) {
253         root->rr = deleteTree(root->rr);
254     }
255     delete root;
256     root = NULL;
257 
258     return NULL;
259 }
260 
261 int main()
262 {
263     int ci, cc;
264     int i, j;
265     int x, y;
266     st *root;
267 
268     while (scanf("%d", &cc) == 1) {
269         for (ci = 0; ci < cc; ++ci) {
270             // data initialization 
271             memset(hash_key, 0, MAXN * sizeof(int));
272             memset(key_hash, 0, MAXN * sizeof(int));
273             memset(depth, 0, MAXN * sizeof(int));
274             memset(anc, 0, MAXN * 16 * sizeof(int));
275             nc = 0;
276             root = NULL;
277 
278             constructBinaryTree(root);
279             getParent(root);
280             getDepth(root, 1);
281             for (j = 1; j < 16; ++j) {
282                 for (i = 1; i <= nc; ++i) {
283                     anc[i][j] = anc[anc[i][j - 1]][j - 1];
284                 }
285             }
286             scanf("%d%d", &x, &y);
287             if (hash_key[x] == 0 || hash_key[y] == 0) {
288                 printf("My God
");
289             } else {
290                 printf("%d
", key_hash[leastCommonAncestor(hash_key[x], hash_key[y])]);
291             }
292 
293             root = deleteTree(root);
294         }
295     }
296 
297     return 0;
298 }
299 */
原文地址:https://www.cnblogs.com/zhuli19901106/p/3539127.html