剑指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\n", tree[s1][3]); 117 } else { 118 // At least one value is not found in the tree. 119 printf("My God\n"); 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\n"); 289 } else { 290 printf("%d\n", key_hash[leastCommonAncestor(hash_key[x], hash_key[y])]); 291 } 292 293 root = deleteTree(root); 294 } 295 } 296 297 return 0; 298 } 299 */