Binarytree练习二叉树序列化反序列化606、331、652、297

297. 二叉树的序列化与反序列化

序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。
题解:
1)BFS
序列化:通用BFS
反序列化:每次遍历2个节点 这2个节点是出队节点的左右孩子

2)DFS 递归(画写看
序列化:求二叉树的先序遍历序列
反序列化:通过序列化得到的先序遍历序列 构建原二叉树

sloution:
1)BFS 序列化: 队列

 public String serialize(TreeNode root) {
        if(root==null){
            return "";
        }
        StringBuilder res=new StringBuilder();
        Queue<TreeNode> queue=new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            TreeNode cur=queue.poll();
            if(cur==null){
                res.append("null,");
            }
            else{
               res.append(String.valueOf(cur.val));
               res.append(",");
               queue.offer(cur.left);
               queue.offer(cur.right);
            }
        }  
        return res.toString();
    }
作者:carryzz

BFS 反序列化:

    public TreeNode deserialize(String data) {
        if(data.equals("")){
            return null;
        }
        String []temp=data.split(",");
        TreeNode root=new TreeNode(Integer.valueOf(temp[0]));
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);//首出队节点
        TreeNode cur=root;
        
        for(int i=1;i<temp.length;){
            cur=queue.poll();//出队节点 遍历其左右孩子
            if(!temp[i].equals("null")){
                cur.left=new TreeNode(Integer.valueOf(temp[i]));
                queue.offer(cur.left);

            }
            i+=1;
            if(!temp[i].equals("null")){
                cur.right=new TreeNode(Integer.valueOf(temp[i]));
                queue.offer(cur.right);
            }
            i+=1;
        }
        return root;
    }
}

作者:carryzz

2)DFS 序列化: 求先序遍历

public class Codec {
    public String serialize(TreeNode root) {
        StringBuilder res=mySeri(root,new StringBuilder());
        return res.toString();
    }

    StringBuilder mySeri(TreeNode root,StringBuilder sb){
        if(root==null){
            sb.append("null,");
            return sb;
        }
        else if(root!=null){
            sb.append(root.val);
            sb.append(",");
            
            mySeri(root.left,sb);
            mySeri(root.right,sb);
        }
        return sb;
    }

作者:carryzz

DFS反序列化:

 public TreeNode deserialize(String data) {
        String []temp=data.split(","); // 将序列化的结果转为字符串数组
        List<String> list=new LinkedList<>(Arrays.asList(temp)); // 字符串数组转为集合类 便于操作
        return myDeSeri(list);
    }
    public TreeNode myDeSeri(List<String> list){
        TreeNode root;
        if(list.get(0).equals("null")){
            list.remove(0); // 删除第一个元素 则第二个元素成为新的首部 便于递归 
            return null;
        }
        else{
            root=new TreeNode(Integer.valueOf(list.get(0)));
            list.remove(0);
            root.left=myDeSeri(list);
            root.right=myDeSeri(list);
        }
        return root;
    }
}

作者:carryzz

/**
* 构建树的函数 buildTree 接收的 “状态” 是 list 数组,由序列化字符串转成
* 按照前序遍历的顺序:先构建根节点,再构建左子树、右子树
* 将 list 数组的首项弹出,它是当前子树的 root 节点
* 如果它为 ‘X’ ,返回 null
* 如果它不为 ‘X’,则为它创建节点,并递归调用 buildTree 构建左右子树,当前子树构建完毕,向上返回
*/

        public TreeNode deserialize(String data) {
            String[] temp = data.split(",");
            Deque<String> dp = new LinkedList<>(Arrays.asList(temp));
            return buildTree(dp);
        }
        private TreeNode buildTree(Deque<String> dq){
            String s = dq.poll(); //返回当前结点
            if (s.equals("X")) return null;
            TreeNode node = new TreeNode(Integer.parseInt(s));
            node.left = buildTree(dq); //构建左子树
            node.right = buildTree(dq); //构建右子树
            return node;
        }
    }

注:

1)Queue 中 remove() 和 poll()都是用来从队列头部删除一个元素。 在队列元素为空的情况下,remove()方法会抛NoSuchElementException异常,poll() 方法只会返回 null 。

2)Queue 中 add() 和offer()都是用来向队列添加一个元素。 在容量已满的情况下,add()方法会抛出IllegalStateException异常,offer() 方法只会返回 false 。

3)String.valueOf(int i) : 将 int 变量 i 转换成字符串

4)toString(): 返回表示 Integer 值的 String 对象。

5)Integer. valueOf()方法的作用
Integer. valueOf()可以将基本类型int转换为包装类型Integer
或者将String转换成Integer,String如果为Null或“”都会报错

6)split分割字符串
1、如果用“.”作为分隔的话,必须是如下写法:String.split("\."),这样才能正确的分隔开,不能用String.split(".");
2、如果用“|”作为分隔的话,必须是如下写法:String.split("\|"),这样才能正确的分隔开,不能用String.split("|");
“.”和“|”都是转义字符,必须得加"\";

7)Arrays.asList() 将一个数组转化为一个List对象,这个方法会返回一个ArrayList类型的对象。

331. 验证二叉树的前序序列化

序列化二叉树的一种方法是使用前序遍历。当我们遇到一个非空节点时,我们可以记录下这个节点的值。如果它是一个空节点,我们可以使用一个标记值记录,例如 #。

例如,上面的二叉树可以被序列化为字符串 “9,3,4,#,#,1,#,#,2,#,6,#,#”,其中 # 代表一个空节点。

给定一串以逗号分隔的序列,验证它是否是正确的二叉树的前序序列化。编写一个在不重构树的条件下的可行算法。

每个以逗号分隔的字符或为一个整数或为一个表示 null 指针的 ‘#’ 。

你可以认为输入格式总是有效的,例如它永远不会包含两个连续的逗号,比如 “1,3” 。

示例 1:

输入: “9,3,4,#,#,1,#,#,2,#,6,#,#”
输出: true
示例 2:

输入: “1,#”
输出: false
示例 3:

输入: “9,#,#,1”
输出: false

题解:
1)字符串转换为字符数组方便操作
2)叶子结点和非叶子结点数目差1
sloution:

class Solution {
    public boolean isValidSerialization(String preorder) {
    String[] str = preorder.split(",");
    int nnum=0;
    int inum=0;

    for(int i=0;i<str.length;i++){
    if(nnum> inum) return false;
    if(str[i].equals("#")) nnum++;
    else inum++;
    }
    return (nnum - inum) == 1;
    }
}

606. 根据二叉树创建字符串

你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。
空节点则用一对空括号 “()” 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
题解:左子树为空时用()替代节点,如果右子树为空或者左右子树都为空不用。

参考sloution:

class Solution {
    //前序遍历
    TreeNode pre = null;

    public String tree2str(TreeNode t) {
        if (t == null) return "";
        StringBuilder sb = new StringBuilder();
        helper(t, pre, sb);
        return sb.substring(1, sb.length() - 1);
    }

    private void helper(TreeNode root, TreeNode pre, StringBuilder sb) {
        if (root == null) return;
        //前序遍历
        //1.如果当前节点为父节点的右子树且左子树为空,括号不能省略
        if (pre != null && pre.left == null && pre.right == root) {
            sb.append("()");
        }
        sb.append("(").append(root.val);
        pre = root;
        helper(root.left, pre, sb);
        helper(root.right, pre, sb);
        //遍历完当前节点后关闭括号
        sb.append(")");
    }
}

运算速度比较(通常情况下):
StringBuilder > StringBuffer > String

String是final类不能被继承且为字符串常量,而StringBuilder和StringBuffer均为字符串变量。String对象一旦创建便不可更改,而后两者是可更改的,它们只能通过构造函数来建立对象,且对象被建立以后将在内存中分配内存空间,并初始保存一个null,通过append方法向StringBuffer和StringBuilder中赋值。

引用自:String,StringBuilder和StringBuffer
652【hashmap】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值