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


    2014-03-19 04:48

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

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

    代码:

      1 // 4.7 Least Common Ancestor
      2 // This solution is Naive Algorithm, may timeout on very large and skewed trees.
      3 #include <cstdio>
      4 #include <cstring>
      5 using namespace std;
      6 
      7 const int MAXN = 10005;
      8 // tree[x][0]: parent of node x
      9 // tree[x][1]: left child of node x
     10 // tree[x][2]: right child of node x
     11 // tree[x][3]: value of node x
     12 int tree[MAXN][4];
     13 // number of nodes
     14 int e;
     15 
     16 void build(int a)
     17 {
     18     int tmp;
     19 
     20     scanf("%d", &tmp);
     21     if(tmp)
     22     {
     23         tree[a][1] = e;
     24         tree[e][3] = tmp;
     25         tree[e][0] = a;
     26         ++e;
     27         // build the left subtree
     28         build(e - 1);
     29     }
     30 
     31     scanf("%d", &tmp);
     32     if(tmp)
     33     {
     34         tree[a][2] = e;
     35         tree[e][3] = tmp;
     36         tree[e][0] = a;
     37         ++e;
     38         // build the right subtree
     39         build(e - 1);
     40     }
     41 }
     42 
     43 int main()
     44 {
     45     int n, ni;
     46     int i;
     47     // the value to be queried
     48     int m1, m2;
     49     // the corresponding node indices of m1 and m2
     50     int s1, s2;
     51     int t1, t2;
     52     int c1, c2, c;
     53 
     54     while (scanf("%d", &n)  == 1) {
     55         for (ni = 0; ni < n; ++ni) {
     56             // get value for root node
     57             e = 1;
     58             scanf("%d", &tree[0][3]);
     59 
     60             // root has no parent node
     61             tree[0][0] = -1;
     62             build(0);
     63 
     64             while (scanf("%d%d", &m1, &m2) == 2 && (m1 && m2)) {
     65                 s1 = s2 = -1;
     66                 for (i = 0;i <= e; ++i) {
     67                     if (tree[i][3] == m1) {
     68                         s1 = i;
     69                         // there're duplicate values
     70                         break;
     71                     }
     72                 }
     73                 for (i = 0;i <= e; ++i) {
     74                     if (tree[i][3] == m2) {
     75                         s2 = i;
     76                         // there're duplicate values
     77                         break;
     78                     }
     79                 }
     80 
     81                 if (s1 != -1 && s2 != -1) {
     82                     t1 = s1;
     83                     t2 = s2;
     84                     c1 = c2 = 0;
     85 
     86                     // c1 is the depth of t1
     87                     while (tree[t1][0] != -1) {
     88                         ++c1;
     89                         t1 = tree[t1][0];
     90                     }
     91                     // c2 is the depth of t2
     92                     while (tree[t2][0] != -1) {
     93                         ++c2;
     94                         t2 = tree[t2][0];
     95                     }
     96                 
     97                     // move'em to the same height level
     98                     if (c1 > c2) {
     99                         c = c1 - c2;
    100                         while(c--) {
    101                             s1 = tree[s1][0];
    102                         }
    103                     } else {
    104                         c = c2 - c1;
    105                         while(c--) {
    106                             s2 = tree[s2][0];
    107                         }
    108                     }
    109                 
    110                     while(s1 != s2)
    111                     {
    112                         s1 = tree[s1][0];
    113                         s2 = tree[s2][0];
    114                     }
    115                     printf("%d
    ", tree[s1][3]);
    116                 } else {
    117                     // At least one value is not found in the tree.
    118                     printf("Not found in the tree.
    ");
    119                 }
    120             }
    121         }
    122     }
    123 
    124     return 0;
    125 }

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

    代码:

      1 // 4.7 Least Common Ancestor
      2 // O(log(n)) solution with binary decomposition.
      3 #include <cstdio>
      4 #include <cstring>
      5 using namespace std;
      6 
      7 typedef struct st{
      8 public:
      9     int key;
     10     st *ll;
     11     st *rr;
     12     st(int _key = 0): key(_key), ll(NULL), rr(NULL) {}
     13 }st;
     14 
     15 // maximal number of nodes
     16 const int MAXN = 10005;
     17 // key -> node_index mapping
     18 int hash_key[MAXN];
     19 // node_index -> key mapping
     20 int key_hash[MAXN];
     21 // depth of each node
     22 int depth[MAXN];
     23 // array recording ancestors
     24 int anc[MAXN][16];
     25 // total number of nodes, index starting from 1
     26 int nc;
     27 
     28 // recursively calculate depths of nodes
     29 void getDepth(st *root, int dep)
     30 {
     31     if (root == NULL) {
     32         return;
     33     }
     34     depth[hash_key[root->key]] = dep;
     35     if (root->ll != NULL) {
     36         getDepth(root->ll, dep + 1);
     37     }
     38     if (root->rr != NULL) {
     39         getDepth(root->rr, dep + 1);
     40     }
     41 }
     42 
     43 // recursively construct a binary tree
     44 void constructBinaryTree(st *&root)
     45 {
     46     int tmp;
     47 
     48     scanf("%d", &tmp);
     49     if (tmp == 0) {
     50         root = NULL;
     51     } else {
     52         root = new st(tmp);
     53         ++nc;
     54         if (hash_key[tmp] == 0) {
     55             hash_key[tmp] = nc;
     56         }
     57         key_hash[nc] = tmp;
     58         constructBinaryTree(root->ll);
     59         constructBinaryTree(root->rr);
     60     }
     61 }
     62 
     63 // recursively initialize ancestor array
     64 void getParent(st *root)
     65 {
     66     if (root == NULL) {
     67         return;
     68     }
     69 
     70     // anc[x][0] is the direct parent of x.
     71     if (root->ll != NULL) {
     72         anc[hash_key[root->ll->key]][0] = hash_key[root->key];
     73         getParent(root->ll);
     74     }
     75     if (root->rr != NULL) {
     76         anc[hash_key[root->rr->key]][0] = hash_key[root->key];
     77         getParent(root->rr);
     78     }
     79 }
     80 
     81 // calculate LCA in O(log(n)) time
     82 int leastCommonAncestor(int x, int y)
     83 {
     84     int i;
     85 
     86     if (depth[x] < depth[y]) {
     87         return leastCommonAncestor(y, x);
     88     }
     89     for (i = 15; i >= 0; --i) {
     90         if (depth[anc[x][i]] >= depth[y]) {
     91             x = anc[x][i];
     92             if (depth[x] == depth[y]) {
     93                 break;
     94             }
     95         }
     96     }
     97     if (x == y) {
     98         return x;
     99     }
    100 
    101     for (i = 15; i >= 0; --i) {
    102         if (anc[x][i] != anc[y][i]) {
    103             // they'll finally be equal, think about the reason.
    104             x = anc[x][i];
    105             y = anc[y][i];
    106         }
    107     }
    108 
    109     // this is the direct parent of x
    110     return anc[x][0];
    111 }
    112 
    113 st *deleteTree(st *root)
    114 {
    115     if (NULL == root) {
    116         return NULL;
    117     }
    118 
    119     if (root->ll != NULL) {
    120         root->ll = deleteTree(root->ll);
    121     }
    122     if (root->rr != NULL) {
    123         root->rr = deleteTree(root->rr);
    124     }
    125     delete root;
    126     root = NULL;
    127 
    128     return NULL;
    129 }
    130 
    131 int main()
    132 {
    133     int ci, cc;
    134     int i, j;
    135     int x, y;
    136     st *root;
    137 
    138     while (scanf("%d", &cc) == 1) {
    139         for (ci = 0; ci < cc; ++ci) {
    140             // data initialization 
    141             memset(hash_key, 0, MAXN * sizeof(int));
    142             memset(key_hash, 0, MAXN * sizeof(int));
    143             memset(depth, 0, MAXN * sizeof(int));
    144             memset(anc, 0, MAXN * 16 * sizeof(int));
    145             nc = 0;
    146             root = NULL;
    147 
    148             constructBinaryTree(root);
    149             getParent(root);
    150             getDepth(root, 1);
    151             for (j = 1; j < 16; ++j) {
    152                 for (i = 1; i <= nc; ++i) {
    153                     anc[i][j] = anc[anc[i][j - 1]][j - 1];
    154                 }
    155             }
    156             while (scanf("%d%d", &x, &y) == 2 && (x && y)) {
    157                 if (hash_key[x] == 0 || hash_key[y] == 0) {
    158                     printf("Not found in the tree.
    ");
    159                 } else {
    160                     printf("%d
    ", key_hash[leastCommonAncestor(hash_key[x], hash_key[y])]);
    161                 }
    162             }
    163 
    164             root = deleteTree(root);
    165         }
    166     }
    167 
    168     return 0;
    169 }

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

    代码:

      1 // 4.7 Least Common Ancestor
      2 // Tarjan Offline Algorithm
      3 #include <cstdio>
      4 #include <cstdlib>
      5 #include <unordered_map>
      6 #include <unordered_set>
      7 using namespace std;
      8 
      9 struct TreeNode {
     10     int val;
     11     TreeNode *left;
     12     TreeNode *right;
     13     
     14     TreeNode(int _val = 0): val(_val), left(nullptr), right(nullptr) {};
     15 };
     16 
     17 void constructTree(vector<TreeNode *> &nodes, 
     18                    unordered_set<TreeNode *> &checked)
     19 {
     20     int ll, rr;
     21     int i;
     22 
     23     for (i = 0; i < (int)nodes.size(); ++i) {
     24         checked.insert(nodes[i]);
     25     }
     26     for (i = 0; i < (int)nodes.size(); ++i) {
     27         scanf("%d%d", &ll, &rr);
     28         if (ll > 0) {
     29             nodes[i]->left = nodes[ll - 1];
     30             checked.erase(nodes[ll - 1]);
     31         }
     32         if (rr > 0) {
     33             nodes[i]->right = nodes[rr - 1];
     34             checked.erase(nodes[rr - 1]);
     35         }
     36     }
     37 }
     38 
     39 TreeNode *findRoot(TreeNode *node, unordered_map<TreeNode *, TreeNode *> &disjoint_set)
     40 {
     41     if (node != disjoint_set[node]) {
     42         disjoint_set[node] = findRoot(disjoint_set[node], disjoint_set);
     43     }
     44     
     45     return disjoint_set[node];
     46 }
     47 
     48 void tarjanLCA(TreeNode *root, unordered_map<TreeNode *, TreeNode *> &disjoint_set, 
     49                unordered_map<TreeNode *, unordered_map<TreeNode *, TreeNode *> > &query, 
     50                unordered_set<TreeNode *> &checked)
     51 {
     52     if (root == nullptr) {
     53         return;
     54     }
     55     
     56     disjoint_set[root] = root;
     57     if (root->left != nullptr) {
     58         tarjanLCA(root->left, disjoint_set, query, checked);
     59         disjoint_set[root->left] = root;
     60     }
     61     if (root->right != nullptr) {
     62         tarjanLCA(root->right, disjoint_set, query, checked);
     63         disjoint_set[root->right] = root;
     64     }
     65     checked.insert(root);
     66     
     67     if (query.find(root) == query.end()) {
     68         return;
     69     }
     70     
     71     unordered_map<TreeNode *, TreeNode *>::iterator it;
     72     for (it = query[root].begin(); it != query[root].end(); ++it) {
     73         if (it->second != nullptr) {
     74             // already solved, skip it
     75             continue;
     76         }
     77         if (checked.find(it->first) != checked.end()) {
     78             query[root][it->first] = query[it->first][root] = findRoot(it->first, disjoint_set);
     79         }
     80     }
     81 }
     82 
     83 int main()
     84 {
     85     int n;
     86     int i;
     87     int val;
     88     vector<TreeNode *> nodes;
     89     TreeNode *root;
     90     unordered_map<TreeNode *, TreeNode *> disjoint_set;
     91     unordered_map<TreeNode *, unordered_map<TreeNode *, TreeNode *> > query;
     92     unordered_map<TreeNode *, unordered_map<TreeNode *, TreeNode *> >::iterator it1;
     93     unordered_set<TreeNode *> checked;
     94     unordered_map<TreeNode *, TreeNode *>::iterator it2;
     95     int idx1, idx2;
     96     
     97     while (scanf("%d", &n) == 1 && n > 0) {
     98         nodes.resize(n);
     99         for (i = 0; i < n; ++i) {
    100             scanf("%d", &val);
    101             nodes[i] = new TreeNode(val);
    102         }
    103         constructTree(nodes, checked);
    104         root = *(checked.begin());
    105         checked.clear();
    106         
    107         while (scanf("%d%d", &idx1, &idx2) == 2 && (idx1 >= 0 && idx2 >= 0)) {
    108             if (idx1 > idx2) {
    109                 i = idx1;
    110                 idx1 = idx2;
    111                 idx2 = i;
    112             }
    113             query[nodes[idx1]][nodes[idx2]] = nullptr;
    114             query[nodes[idx2]][nodes[idx1]] = nullptr;
    115         }
    116         // Tarjan Offline Algorithm
    117         tarjanLCA(root, disjoint_set, query, checked);
    118         
    119         // print the results
    120         for (it1 = query.begin(); it1 != query.end(); ++it1) {
    121             for (it2 = (it1->second).begin(); it2 != (it1->second).end(); ++it2) {
    122                 if (it1->first->val > it2->first->val) {
    123                     continue;
    124                 }
    125                 printf("The least common ancestor of %d and %d is %d.
    ", 
    126                        it1->first->val, it2->first->val, it2->second->val);
    127             }
    128         }
    129         
    130         // clear up
    131         disjoint_set.clear();
    132         checked.clear();
    133         for (it1 = query.begin(); it1 != query.end(); ++it1) {
    134             (it1->second).clear();
    135         }
    136         query.clear();
    137     }
    138     
    139     return 0;
    140 }
  • 相关阅读:
    ORACLE定时备份
    解压cpio.gz
    Fusioncharts的数字格式化
    linux apache+php+mysql安装及乱码解决办法
    两个Beta函数类型的积分及其一般形式
    【转载】巴塞尔问题(Basel Problem)的多种解法
    两本关于各种刁钻积分计算的书
    一个超几何函数类型的积分
    一个取整函数积分的一般形式
    Clausen Functions (and related series, functions, integrals)
  • 原文地址:https://www.cnblogs.com/zhuli19901106/p/3610479.html
Copyright © 2020-2023  润新知