2014-05-08 08:26

题目链接

原题:

Given a preorder traversal, create a binary search tree in optimized time

题目:给定一个二叉搜索树的前序遍历,请重建这棵树。要求最优化算法。

解法1:这人每次出题都要求“最优算法”,自己写的代码却实在让人汗颜,让人觉得这家伙就是懒得思考,想从别人那儿问答案。前序遍历的顺序是“根左右”,那么根节点之后所有小于根的部分就是左子树,后面就是右子树了。怎么找这条分界线呢?可以顺着找。那么算法的复杂度就是O(n * log(n))了。复杂度的证明参考归并排序即可。这个算法可行,但不是最优。

代码:

 1 // http://www.careercup.com/question?id=5162732873580544
 2 #include <iostream>
 3 #include <vector>
 4 using namespace std;
 5 
 6 struct TreeNode {
 7     int val;
 8     TreeNode *left;
 9     TreeNode *right;
10     TreeNode(int _val = 0): val(_val), left(nullptr), right(nullptr) {};
11 };
12 
13 void constructBSTFromPreorderTraversal(vector<int> &v, int ll, int rr, TreeNode *&root)
14 {
15     root = new TreeNode(v[ll]);
16 
17     int i = ll + 1;
18     while (i <= rr && v[i] < v[ll]) {
19         ++i;
20     }
21     if (ll + 1 <= i - 1) {
22         constructBSTFromPreorderTraversal(v, ll + 1, i - 1, root->left);
23     }
24     if (i <= rr) {
25         constructBSTFromPreorderTraversal(v, i, rr, root->right);
26     }
27 }
28 
29 void inorderTraversal(TreeNode *root)
30 {
31     if (nullptr == root) {
32         return;
33     }
34     inorderTraversal(root->left);
35     cout << root->val << ' ';
36     inorderTraversal(root->right);
37 }
38 
39 void clearTree(TreeNode *&root)
40 {
41     if (nullptr == root) {
42         return;
43     }
44     clearTree(root->left);
45     clearTree(root->right);
46     delete root;
47     root = nullptr;
48 }
49 
50 int main()
51 {
52     vector<int> v;
53     int n;
54     int i;
55     TreeNode *root;
56     
57     while (cin >> n && n > 0) {
58         v.resize(n);
59         for (i = 0; i < n; ++i) {
60             cin >> v[i];
61         }
62         root = nullptr;
63         constructBSTFromPreorderTraversal(v, 0, n - 1, root);
64         inorderTraversal(root);
65         cout << endl;
66         
67         clearTree(root);
68         v.clear();
69     }
70     
71     return 0;
72 }

解法2:既然遍历是O(n)时间完成的,重建应该也可以做到O(n)。我的思路,是比较三个节点的值:父节点,当前节点,新节点。根据它们之间的大小关系可以判断新的节点应该插入在哪儿。代码中的关键部分很短,所以不需要多余解释了。其中用到了一个节点栈,用于回溯。所以这个算法用递归来写也是同样直观的。

 1 // http://www.careercup.com/question?id=5162732873580544
 2 #include <iostream>
 3 #include <vector>
 4 using namespace std;
 5 
 6 struct TreeNode {
 7     int val;
 8     TreeNode *left;
 9     TreeNode *right;
10     TreeNode(int _val = 0): val(_val), left(nullptr), right(nullptr) {};
11 };
12 
13 void inorderTraversal(TreeNode *root)
14 {
15     if (nullptr == root) {
16         return;
17     }
18     inorderTraversal(root->left);
19     cout << root->val << ' ';
20     inorderTraversal(root->right);
21 }
22 
23 void clearTree(TreeNode *&root)
24 {
25     if (nullptr == root) {
26         return;
27     }
28     clearTree(root->left);
29     clearTree(root->right);
30     delete root;
31     root = nullptr;
32 }
33 
34 int main()
35 {
36     vector<int> v;
37     int n;
38     int i;
39     TreeNode *root;
40     TreeNode *tmp;
41     vector<TreeNode *> st;
42     
43     while (cin >> n && n > 0) {
44         v.resize(n);
45         for (i = 0; i < n; ++i) {
46             cin >> v[i];
47         }
48         
49         root = new TreeNode(v[0]);
50         st.push_back(root);
51         for (i = 1; i < n; ++i) {
52             if (v[i] < st[st.size() - 1]->val) {
53                 tmp = new TreeNode(v[i]);
54                 st[st.size() - 1]->left = tmp;
55                 st.push_back(tmp);
56             } else if (st.size() == 1 || v[i] < st[st.size() - 2]->val) {
57                 tmp = new TreeNode(v[i]);
58                 st[st.size() - 1]->right = tmp;
59                 st.push_back(tmp);
60             } else {
61                 st.pop_back();
62                 --i;
63             }
64         }
65         
66         inorderTraversal(root);
67         cout << endl;
68         
69         v.clear();
70         st.clear();
71         clearTree(root);
72     }
73     
74     return 0;
75 }

 

 posted on 2014-05-08 08:44  zhuli19901106  阅读(170)  评论(0编辑  收藏  举报