题目要求
思路一:先序遍历
- 用先序遍历得到序列化结果,此时第一个元素就是树的根,便于反序列化;
- 先将序列化结果拆分成单个元素的数组,然后递归构建BST:
- 取出当前所遍历子树的根
c
u
r
cur
cur,找到第一个比
c
u
r
cur
cur大的值,其所在下标为
j
j
j;
- 所以
j
j
j左边都比
c
u
r
cur
cur小,为其左子树,右边都比
c
u
r
cur
cur大,为其右子树;
- 递归构建即可。
Java
public class Codec {
public String serialize(TreeNode root) {
if(root == null)
return null;
List<String> list = new ArrayList<>();
preOrder(root, list);
StringBuilder sb = new StringBuilder();
for(int i = 0; i < list.size(); i++) {
sb.append(list.get(i));
if(i != n - 1)
sb.append(",");
}
return sb.toString();
}
void preOrder(TreeNode root, List<String> list) {
if(root == null)
return ;
list.add(String.valueOf(root.val));
preOrder(root.left, list);
preOrder(root.right, list);
}
public TreeNode deserialize(String data) {
if(data == null)
return null;
String[] sSplit = data.split(",");
return DFS(0, sSplit.length - 1, sSplit);
}
TreeNode DFS(int l, int r, String[] ss) {
if(l > r)
return null;
int j = l + 1, cur = Integer.parseInt(ss[l]);
TreeNode res = new TreeNode(cur);
while(j <= r && Integer.parseInt(ss[j]) <= cur)
j++;
res.left = DFS(l + 1, j - 1, ss);
res.right = DFS(j, r, ss);
return res;
}
}
- 时间复杂度:序列化复杂度为
O
(
n
)
O(n)
O(n),其中
n
n
n为节点数量;反序列时查找第一个比当前值大的值,对每个节点的扫描次数与当前节点所在深度相关,最坏情况为
O
(
n
2
)
O(n^2)
O(n2),为一条向左下方延伸的链。
- 空间复杂度:
O
(
n
)
O(n)
O(n)
C++
【注意地址符】
class Codec {
public:
string serialize(TreeNode* root) {
vector<string> list;
preOrder(root, list);
if(list.size() == 0)
return "";
string res;
for(int i = 0; i < list.size() - 1; i++)
res.append(list[i] + ",");
res.append(list.back());
return res;
}
void preOrder(TreeNode* root, vector<string> &list) {
if(root == nullptr)
return ;
list.emplace_back(to_string(root->val));
preOrder(root->left, list);
preOrder(root->right, list);
}
TreeNode* deserialize(string data) {
if(data.size() == 0)
return nullptr;
vector<string> sSplit = split(data);
return DFS(0, sSplit.size() - 1, sSplit);
}
TreeNode* DFS(int l, int r, vector<string> &ss) {
if(l > r)
return nullptr;
int j = l + 1, cur = stoi(ss[l]);
TreeNode* res = new TreeNode(cur);
while(j <= r && stoi(ss[j]) <= cur)
j++;
res->left = DFS(l + 1, j - 1, ss);
res->right = DFS(j, r, ss);
return res;
}
vector<string> split(const string &str) {
char dec = ',';
int pos = 0;
int start = 0;
vector<string> res;
while(pos < str.size()) {
while(pos < str.size() && str[pos] == dec)
pos++;
start = pos;
while(pos < str.size() && str[pos] != dec)
pos++;
if(start < str.size())
res.emplace_back(str.substr(start, pos - start));
}
return res;
}
};
- 时间复杂度:序列化复杂度为
O
(
n
)
O(n)
O(n),其中
n
n
n为节点数量;反序列时查找第一个比当前值大的值,对每个节点的扫描次数与当前节点所在深度相关,最坏情况为
O
(
n
2
)
O(n^2)
O(n2),为一条向左下方延伸的链。
- 空间复杂度:
O
(
n
)
O(n)
O(n)
思路二:二分查找
- 和上面一样,只不过在反序列化时,采用二分查找第一个大于当前值的位置。
Java
public class Codec {
public String serialize(TreeNode root) {
if(root == null)
return null;
List<String> list = new ArrayList<>();
preOrder(root, list);
int n = list.size();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < n; i++) {
sb.append(list.get(i));
if(i != n - 1)
sb.append(",");
}
return sb.toString();
}
void preOrder(TreeNode root, List<String> list) {
if(root == null)
return ;
list.add(String.valueOf(root.val));
preOrder(root.left, list);
preOrder(root.right, list);
}
public TreeNode deserialize(String data) {
if(data == null)
return null;
String[] sSplit = data.split(",");
return DFS(0, sSplit.length - 1, sSplit);
}
TreeNode DFS(int l, int r, String[] ss) {
if(l > r)
return null;
int ll = l + 1, rr = r, cur = Integer.parseInt(ss[l]);
while(ll < rr) {
int m = ll + rr >> 1;
if(Integer.parseInt(ss[m]) > cur)
rr = m;
else
ll = m + 1;
}
if(Integer.parseInt(ss[rr]) <= cur)
rr++;
TreeNode res = new TreeNode(cur);
res.left = DFS(l + 1, rr - 1, ss);
res.right = DFS(rr, r, ss);
return res;
}
}
- 时间复杂度:序列化复杂度为
O
(
n
)
O(n)
O(n),其中
n
n
n为节点数量;反序列时采用二分查找第一个比当前值大的值,此时最坏情况为
O
(
n
log
?
n
)
O(n\log n)
O(nlogn),为一条向左下方延伸的链。
- 空间复杂度:
O
(
n
)
O(n)
O(n)
C++
class Codec {
public:
string serialize(TreeNode* root) {
vector<string> list;
preOrder(root, list);
if(list.size() == 0)
return "";
string res;
for(int i = 0; i < list.size() - 1; i++)
res.append(list[i] + ",");
res.append(list.back());
return res;
}
void preOrder(TreeNode* root, vector<string> &list) {
if(root == nullptr)
return ;
list.emplace_back(to_string(root->val));
preOrder(root->left, list);
preOrder(root->right, list);
}
TreeNode* deserialize(string data) {
if(data.size() == 0)
return nullptr;
vector<string> sSplit = split(data);
return DFS(0, sSplit.size() - 1, sSplit);
}
TreeNode* DFS(int l, int r, vector<string> &ss) {
if(l > r)
return nullptr;
int ll = l + 1, rr = r, cur = stoi(ss[l]);
while(ll < rr) {
int m = (ll + rr) >> 1;
if(stoi(ss[m]) > cur)
rr = m;
else
ll = m + 1;
}
if(stoi(ss[rr]) <= cur)
rr++;
TreeNode* res = new TreeNode(cur);
res->left = DFS(l + 1, rr - 1, ss);
res->right = DFS(rr, r, ss);
return res;
}
vector<string> split(const string &str) {
char dec = ',';
int pos = 0;
int start = 0;
vector<string> res;
while(pos < str.size()) {
while(pos < str.size() && str[pos] == dec)
pos++;
start = pos;
while(pos < str.size() && str[pos] != dec)
pos++;
if(start < str.size())
res.emplace_back(str.substr(start, pos - start));
}
return res;
}
};
- 时间复杂度:序列化复杂度为
O
(
n
)
O(n)
O(n),其中
n
n
n为节点数量;反序列时采用二分查找第一个比当前值大的值,此时最坏情况为
O
(
n
log
?
n
)
O(n\log n)
O(nlogn),为一条向左下方延伸的链。
- 空间复杂度:
O
(
n
)
O(n)
O(n)
思路三:后序遍历+栈
java
public class Codec {
public String serialize(TreeNode root) {
if(root == null)
return null;
List<String> list = new ArrayList<>();
postOrder(root, list);
int n = list.size();
StringBuilder sb = new StringBuilder();
for(int i = 0; i < n; i++) {
sb.append(list.get(i));
if(i != n - 1)
sb.append(",");
}
return sb.toString();
}
void postOrder(TreeNode root, List<String> list) {
if(root == null)
return ;
postOrder(root.left, list);
postOrder(root.right, list);
list.add(String.valueOf(root.val));
}
public TreeNode deserialize(String data) {
if(data == null)
return null;
String[] sSplit = data.split(",");
Deque<Integer> stack = new ArrayDeque<Integer>();
for(int i = 0; i < sSplit.length; i++)
stack.push(Integer.parseInt(sSplit[i]));
return DFS(Integer.MIN_VALUE, Integer.MAX_VALUE, stack);
}
TreeNode DFS(int low, int up, Deque<Integer> stack) {
if(stack.isEmpty() || stack.peek() < low || stack.peek() > up)
return null;
int cur = stack.pop();
TreeNode res = new TreeNode(cur);
res.right = DFS(cur, up, stack);
res.left = DFS(low, cur, stack);
return res;
}
}
- 时间复杂度:序列化和反序列化均为
O
(
n
)
O(n)
O(n)
- 空间复杂度:
O
(
n
)
O(n)
O(n)
C++
class Codec {
public:
string serialize(TreeNode* root) {
vector<string> list;
postOrder(root, list);
if(list.size() == 0)
return "";
string res;
for(int i = 0; i < list.size() - 1; i++)
res.append(list[i] + ",");
res.append(list.back());
return res;
}
void postOrder(TreeNode* root, vector<string> &list) {
if(root == nullptr)
return ;
postOrder(root->left, list);
postOrder(root->right, list);
list.emplace_back(to_string(root->val));
}
TreeNode* deserialize(string data) {
if(data.size() == 0)
return nullptr;
vector<string> sSplit = split(data);
stack<int> stack;
for(auto &s : sSplit)
stack.emplace(stoi(s));
return DFS(INT_MIN, INT_MAX, stack);
}
TreeNode* DFS(int low, int up, stack<int>& stack) {
if(stack.size() == 0 || stack.top() <low || stack.top() > up)
return nullptr;
int cur = stack.top();
stack.pop();
TreeNode* res = new TreeNode(cur);
res->right = DFS(cur, up, stack);
res->left = DFS(low, cur, stack);
return res;
}
vector<string> split(const string &str) {
char dec = ',';
int pos = 0;
int start = 0;
vector<string> res;
while(pos < str.size()) {
while(pos < str.size() && str[pos] == dec)
pos++;
start = pos;
while(pos < str.size() && str[pos] != dec)
pos++;
if(start < str.size())
res.emplace_back(str.substr(start, pos - start));
}
return res;
}
};
- 时间复杂度:序列化和反序列化均为
O
(
n
)
O(n)
O(n)
- 空间复杂度:
O
(
n
)
O(n)
O(n)
总结
一道快乐的递归遍历题~
【补觉day,最近拖延症发作】
|