剑指offer面试题37(java版):序列化二叉树

welcome to my blog

剑指offer面试题37(java版):序列化二叉树

题目描述

请实现两个函数,分别用来序列化和反序列化二叉树

第四次做; 核心: 1) 二叉树的遍历 2)保留结构信息: 左右孩子, 空节点 3)分隔符 4)使用StringBuilder, 别使用String, 避免在字符串常量池中创建大量的无用字符串

public class Codec {
    // Encodes a tree to a single string.
    //递归; 二叉树的遍历, 采用前序遍历, 1)要保留结构信息(除了左右孩子, 还要考虑null), 2)要设置间隔符, 从而区分不同的val
    public String serialize(TreeNode root) {
        //base case
        if(root==null)
            return "#!";
        StringBuilder sb = new StringBuilder();
        sb.append(root.val).append("!");
        sb.append(serialize(root.left));
        sb.append(serialize(root.right));
        return sb.toString();
    }


    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        String[] strs = data.split("!");
        return core(strs);
    }
    private int i;
    //二叉树的遍历, 前序遍历, 递归
    private TreeNode core(String[] strs){
        //base case
        if(i==strs.length)
            return null;
        if(strs[i].equals("#")){
            i++; //索引++
            return null;
        }
        TreeNode root = new TreeNode(Integer.parseInt(strs[i]));
        i++;
        root.left = core(strs);
        root.right = core(strs);
        return root;
    }
}

笔记

  • java基础得牢固才行啊…
  • String.valueOf(“15”)
  • Integer.parseInt(“15”)
  • str.split("")

思路

  • 要对递归有感觉
  • 使用了一个全局变量作为字符串数组的索引, 索引值在每次递归中改变
  • 序列化和反序列化都使用了递归函数
  • 我最开始犯错了, 把根节点的创建放在了函数外面, 结果导致逻辑混乱, 要把操作放在函数内部

第三次做; 结构信息的保存, 具体就是保存空节点; 需要一个全局索引; 反序列化中的while不需要越界检查, 因为序列化过程中数字的后面一定有个叹号

/*
结构信息的保存, 体现在空节点的处理上: 一定要以某种形式保存空节点!
*/
public class Solution {
    String Serialize(TreeNode root) {
        if(root==null)
            return "#";
        //前序: 根左右
        return root.val+"!" + Serialize(root.left) + Serialize(root.right);
  }
    int index = 0;
    TreeNode Deserialize(String str) {
       if(str==null || index==str.length())
           return null;
        if(str.charAt(index)=='#'){
            index++;
            return null;
        }
        int i;
        String curr="";
        //这个while不用加越界判断index
        while(str.charAt(index)!='!'){
            curr += str.charAt(index);
            index++;
        }
        //跳到!下一个位置
        index++;
        TreeNode root = new TreeNode(Integer.valueOf(curr));
        root.left = Deserialize(str);
        root.right = Deserialize(str);
        return root;
  }
}

第二次做, 认真体会递归

public class Solution {
    String Serialize(TreeNode root) {
        if(root==null)
            return "#";
        //这一句包括对当前参数的处理, 以及更新参数后重新调用递归函数; (要时刻保持清醒:传入的参数和更新后的参数的处理流程都是一样的)
        return root.val+"!"+Serialize(root.left)+Serialize(root.right);
  }
    int index = 0;
    TreeNode Deserialize(String str) {
       if(index == str.length())
           return null;
        if(str.charAt(index) == '#'){
            index++;
            return null;
        }
        String curr = "";
        while(str.charAt(index) != '!'){
            curr = curr + str.charAt(index);
            index++;
        }
        TreeNode node = new TreeNode(Integer.valueOf(curr));
        //跳过叹号
        index++;
        node.left = Deserialize(str);
        node.right = Deserialize(str);
        return node;
  }
}
public class Solution {
   public String Serialize(TreeNode root) {
       //input check 
       if(root == null)
           return "";
        StringBuffer sb = new StringBuffer();
        SerializeCore(root, sb);
        return sb.toString();
    }
    public void SerializeCore(TreeNode root, StringBuffer sb){
        //递归函数功能: 将当前节点的值存在String中
        if(root == null){
            sb.append("#,");
        }
        else{
            //根左右
            sb.append(String.valueOf(root.val)+','); // StringBuffer会自动将int转成字符串
            SerializeCore(root.left, sb);
            SerializeCore(root.right, sb);
        }
    }
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
    public TreeNode Deserialize(String str) {
        // input check
        if(str.length() < 1 )
            return null;
        //execute
        String[] s = str.split(",");
        TreeNode root = new TreeNode(Integer.parseInt(s[0]));
        return DeserializeCore(s);
    }
    public int index = 0;
    public TreeNode DeserializeCore(String[] str){
        TreeNode root = null;
        if(index < str.length && str[index].equals("#")){
            index++;
            return null;
        }
        else{ //递归终止条件: index = str.length
            // 在函数内部创建节点, 执行完函数还存在吗? 被外部变量使用的话可能就不会被销毁了, 所以参数中还需要一个指针
            root = new TreeNode(Integer.parseInt(str[index++]) );
            root.left = DeserializeCore(str);
            root.right = DeserializeCore(str);
        }
        return root;
    }
}
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/

精简一些的答案

public class Solution {
    public int index = -1;
    String Serialize(TreeNode root) {
        StringBuffer sb = new StringBuffer();
        if(root == null){
            sb.append("#,");
            return sb.toString();
        }
        sb.append(root.val + ",");
        sb.append(Serialize(root.left));
        sb.append(Serialize(root.right));
        return sb.toString();
  }
    TreeNode Deserialize(String str) {
        index++;
       int len = str.length();
        if(index >= len){
            return null;
        }
        String[] strr = str.split(",");
        TreeNode node = null;
        if(!strr[index].equals("#")){
            node = new TreeNode(Integer.valueOf(strr[index]));
            node.left = Deserialize(str);
            node.right = Deserialize(str);
        }
         
        return node;
  }
}

你可能感兴趣的:(剑指offer,剑指offer)