[leetcode]449. Serialize and Deserialize BST设计BST的编解码

这道题学到了东西。

/*
    一开始想着中序遍历,但是解码的时候才发现,中序遍历并不能唯一得确定二叉树。
    后来看了网上的答案,发现先序遍历是可以的,观察了一下,对于BST,先序遍历确实是可以
    唯一得确定。
    对于一般的二叉树,必须是前序和中序或者后序和中序才能唯一确定,其中中序的作用就是
    确定中心位置,以确定左右子树的前序(后序)的范围
    但是对于BST根据性质,左子树的前序序列最大的就是1st节点,所以找到序列中第一个比
    1st节点大的节点就是右子树的开始,这样就不需要中序了
还有一种方法,保存二叉树的结构信息,这种做法可以应用于任何二叉树。保存结构信息就是空节点添加一个符号代替,解码的时候就知道结构信息了
*/ //记录数据 StringBuilder s = new StringBuilder(); // Encodes a tree to a single string. public String serialize(TreeNode root) { preTra(root); return new String(s); } //前序遍历 public void preTra(TreeNode root) { if (root==null) return; s.append(root.val); s.append(","); preTra(root.left); preTra(root.right); } // Decodes your encoded data to tree. public TreeNode deserialize(String data) { if (data.length()==0) return null; String[] vals = data.split(","); return helper(vals,0,vals.length-1); } //解码过程,和由前序及中序得到二叉树的过程类似 public TreeNode helper(String[] data,int sta,int end) { if (sta > end) return null; //根据BST的特点,获得左右子树前序遍历序列的起止点 int rightSta = rSta(data,sta,end); TreeNode cur = new TreeNode(Integer.parseInt(data[sta])); cur.left = helper(data,sta+1,rightSta-1); cur.right = helper(data,rightSta,end); return cur; } public int rSta(String[] data,int sta,int end) { /* 第一个比根节点大的值就是右子树的开始 */ int a = Integer.parseInt(data[sta]); while (sta<=end) { if (Integer.parseInt(data[sta])>a) break; sta++; } return sta; }

对于普通二叉树,前序(后序)+中序可以唯一确定二叉树,前序(后序)包含父子关系信息,中序包含兄弟关系信息

下边是前序+中序确定二叉树

/*
    * 如果知道(中序遍历和前序遍历)或者(中序遍历和后序遍历)可以唯一确定一棵树*/
    /*
    由前序遍历和中序遍历确定二叉树
     */
    public TreeNode PaI(int[] pre,int[] in)
    {
        if (pre.length==0) return null;
        //只剩下一个节点,就直接返回这个节点
        if (pre.length==1)
            return new TreeNode(pre[0]);
        //根据前序遍历的开头获得中序遍历的中心
        int center = pre[0];
        int c = 0;
        for (int i = 0; i < in.length; i++) {
            if (in[i]==center)
            {
                c = i;
                break;
            }
        }
        //根据中序遍历和中心位置确定左右子树的前中序遍历序列,递归求子树
        //左右子树的中序遍历就是中心位置的左右子序列
        //左右子树的前序遍历序列是根节点后边序列分为的两部分,长度分别与其中序遍历序列长度一样
        TreeNode cur = new TreeNode(center);
        cur.left = PaI(Arrays.copyOfRange(pre,1, 1 + c),Arrays.copyOfRange(in,0,c));
        cur.right = PaI(Arrays.copyOfRange(pre,c+1,pre.length),Arrays.copyOfRange(in,c+1,in.length));
        return cur;
    }

步骤记住两点:所有节点信息都是从前序序列中获得(每次都是根据前序的1st节点信息作为根节点),中序遍历只是用来确定左右子树的子前序的起止点。

然后递归获得左右子树