PAT甲级——A1151 LCA_in_a_BinaryTree【30】

The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U and V as descendants.

Given any two nodes in a binary tree, you are supposed to find their LCA.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers: M (≤ 1,000), the number of pairs of nodes to be tested; and N (≤ 10,000), the number of keys in the binary tree, respectively. In each of the following two lines, N distinct integers are given as the inorder and preorder traversal sequences of the binary tree, respectively. It is guaranteed that the binary tree can be uniquely determined by the input sequences. Then M lines follow, each contains a pair of integer keys U and V. All the keys are in the range of int.

Output Specification:

For each given pair of U and V, print in a line LCA of U and V is A. if the LCA is found and A is the key. But if A is one of U and V, print X is an ancestor of Y. where X is A and Y is the other node. If U or V is not found in the binary tree, print in a line ERROR: U is not found. or ERROR: V is not found. or ERROR: U and V are not found..

Sample Input:

6 8
7 2 3 4 6 5 1 8
5 3 7 2 6 4 8 1
2 6
8 1
7 9
12 -3
0 8
99 99

Sample Output:

LCA of 2 and 6 is 3.
8 is an ancestor of 1.
ERROR: 9 is not found.
ERROR: 12 and -3 are not found.
ERROR: 0 is not found.
ERROR: 99 and 99 are not found.

Solution:
  总结一下寻找最近公共祖先的题目吧:
  最暴力的方法,从上到下,遍历每个节点,对于每个节点的左右子树都判断一下【即向下遍历完其所有的子节点】,a,b节点是否存在,若存在,则更新a,b节点的最近公共祖先即为该节点,从不通过不断向下更新公共祖先,那么最终得到的就是最近的公共祖先节点
  当然,暴力法,我们不提倡,因为永远死在“运行超时”上
  还有一种就是使用深度遍历,判断a,b是否在节点的左右两个子树上,从而得到最近公共祖先节点
  另外一种就是先得到树的所有根节点【类似于重组树,但又不是真的重组】,然后根据节点a,b与每个根节点在中序遍历的位置【所以前提是要有中序遍历】,若,a,b在节点c的两边【包括节点c的位置】,那么c就是最近公共祖先节点

深度遍历方法:  
  使用leetcode第236题的答案讲解一下
  一共有三种特殊情况,root == q 、root == p和root==null,这三种情况均直接返回root即可。
  根据临界条件,实际上可以发现这道题已经被简化为查找以root为根结点的树上是否有p结点或者q结点,如果有就返回p结点或q结点,否则返回null。
  这样一来其实就很简单了,从左右子树分别进行递归,即查找左右子树上是否有p结点或者q结点,就一共有4种情况:
   第一种情况:左子树和右子树均找没有p结点或者q结点;(这里特别需要注意,虽然题目上说了p结点和q结点必定都存在,但是递归的时候必须把所有情况都考虑进去,因为题目给的条件是针对于整棵树,而递归会到局部,不一定都满足整体条件)
   第二种情况:左子树上能找到,但是右子树上找不到,此时就应当直接返回左子树的查找结果;
   第三种情况:右子树上能找到,但是左子树上找不到,此时就应当直接返回右子树的查找结果;
   第四种情况:左右子树上均能找到,说明此时的p结点和q结点分居root结点两侧,此时就应当直接返回root结点了。  
 1 TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
 2         if(root==p||root==q||!root)return root;
 3         
 4         TreeNode* left=lowestCommonAncestor(root->left,  p, q);
 5         TreeNode* right=lowestCommonAncestor(root->right,  p, q);
 6         
 7         if(!left&&!right)return NULL;
 8         else if(left&&!right)return left;
 9         else if(right&&!left)return right;
10         
11         return root;
12     }

先得到根节点方法:

  为本题答案。

 1 #include <iostream>
 2 #include <vector>
 3 #include <unordered_map>
 4 #include <algorithm>
 5 using namespace std;
 6 int n, m;
 7 vector<int>in, pre, root;
 8 unordered_map<int, bool>map;
 9 unordered_map<int, int>local;
10 void DFS(int inL, int inR, int preL, int preR)
11 {
12     if (inL > inR)return;
13     int k = inL;
14     while (k <= inR && in[k] != pre[preL])++k;
15     root.push_back(k);
16     int num = k - inL;
17     DFS(inL, k - 1, preL + 1, preL + num);
18     DFS(k + 1, inR, preL + num + 1, preR);
19 }
20 int main()
21 {
22     cin >> m >> n;
23     in.resize(n);
24     pre.resize(n);    
25     for (int i = 0; i < n; ++i)
26     {
27         cin >> in[i];
28         map[in[i]] = true;
29         local[in[i]] = i;
30     }
31     for (int i = 0; i < n; ++i)
32         cin >> pre[i];
33     DFS(0, n - 1, 0, n - 1);
34     while (m--)
35     {
36         int a, b;
37         cin >> a >> b;
38         if (!map[a] && !map[b])
39             printf("ERROR: %d and %d are not found.\n", a, b);
40         else if(!map[a])
41             printf("ERROR: %d is not found.\n", a);
42         else if(!map[b])
43             printf("ERROR: %d is not found.\n", b);
44         else
45         {
46             int res = 0;
47             for (auto v : root)
48             {
49                 if ((local[a] <= v && local[b] >= v) || (local[a] >= v && local[b] <= v))
50                 {
51                     res = in[v];
52                     break;
53                 }
54             }
55             if (res == a)
56                 printf("%d is an ancestor of %d.\n", a, b);
57             else if (res == b)
58                 printf("%d is an ancestor of %d.\n", b, a);
59             else
60                 printf("LCA of %d and %d is %d.\n", a, b, res);
61         }
62     }
63     return 0;
64 }

  

猜你喜欢

转载自www.cnblogs.com/zzw1024/p/11920695.html