首页>>后端>>java->Java&C++题解与拓展——leetcode449.序列化和反序列化二叉搜索树【么的新知识】

Java&C++题解与拓展——leetcode449.序列化和反序列化二叉搜索树【么的新知识】

时间:2023-12-05 本站 点击:0
每日一题做题记录,参考官方和三叶的题解

题目要求

思路一:先序遍历

用先序遍历得到序列化结果,此时第一个元素就是树的根,便于反序列化;

先将序列化结果拆分成单个元素的数组,然后递归构建BST:

取出当前所遍历子树的根$cur$,找到第一个比$cur$大的值,其所在下标为$j$;

所以$j$左边都比$cur$小,为其左子树,右边都比$cur$大,为其右子树;

递归构建即可。

Java

public class Codec {    // Encodes a tree to a single string.    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);    }    // Decodes your encoded data to tree.    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)$,其中$n$为节点数量;反序列时查找第一个比当前值大的值,对每个节点的扫描次数与当前节点所在深度相关,最坏情况为$O(n^2)$,为一条向左下方延伸的链。

空间复杂度:$O(n)$

C++

【注意地址符】

class Codec {public:    // Encodes a tree to a single string.    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);    }    // Decodes your encoded data to tree.    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)$,其中$n$为节点数量;反序列时查找第一个比当前值大的值,对每个节点的扫描次数与当前节点所在深度相关,最坏情况为$O(n^2)$,为一条向左下方延伸的链。

空间复杂度:$O(n)$

思路二:二分查找

和上面一样,只不过在反序列化时,采用二分查找第一个大于当前值的位置。

Java

public class Codec {    // Encodes a tree to a single string.    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);    }    // Decodes your encoded data to tree.    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)$,其中$n$为节点数量;反序列时采用二分查找第一个比当前值大的值,此时最坏情况为$O(n\log n)$,为一条向左下方延伸的链。

空间复杂度:$O(n)$

C++

class Codec {public:    // Encodes a tree to a single string.    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);    }    // Decodes your encoded data to tree.    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)$,其中$n$为节点数量;反序列时采用二分查找第一个比当前值大的值,此时最坏情况为$O(n\log n)$,为一条向左下方延伸的链。

空间复杂度:$O(n)$

思路三:后序遍历+栈

java

public class Codec {    // Encodes a tree to a single string.    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));    }    // Decodes your encoded data to tree.    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)$

C++

class Codec {public:  // Encodes a tree to a single string.  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));  }  // Decodes your encoded data to tree.  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)$

总结

一道快乐的递归遍历题~

【补觉day,最近拖延症发作】

欢迎指正与讨论! 原文:https://juejin.cn/post/7096455775937101861


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/java/12197.html