算法题 序列化和反序列化二叉搜索树

449. 序列化和反序列化二叉搜索树

问题描述

序列化是将数据结构或对象转换为一系列位的过程,以便它可以存储在文件或内存缓冲区中,或通过网络连接链路传输,以便稍后在同一个或另一个计算机环境中重建。

设计一个算法来序列化和反序列化二叉搜索树。对序列化/反序列化算法的工作方式没有限制。您只需确保二叉搜索树可以序列化为字符串,并且可以将该字符串反序列化为最初的二叉搜索树。

编码的字符串应尽可能紧凑

示例

输入: root = [2,1,3]
输出: [2,1,3]

输入: root = []
输出: []

说明: 你的 Codec 类需要实现 serialize 和 deserialize 两个方法

算法思路

利用BST性质的前序遍历法

  1. 序列化:使用前序遍历(根-左-右),将节点值用分隔符连接成字符串
  2. 反序列化:利用BST性质,递归重建树
    • 第一个值是根节点
    • 小于根节点的值构成左子树
    • 大于根节点的值构成右子树
  3. 由于BST的有序性,不需要存储null节点,可以重建唯一BST

关键

  • BST的前序遍历 + BST性质可以唯一确定树结构
  • 不需要像普通二叉树那样存储null节点,节省空间
  • 反序列化时使用范围限制(min, max)确保BST性质

代码实现

方法一:前序遍历 + 范围限制

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

public class Codec {
   
   
    /**
     * 序列化二叉搜索树
     * 使用前序遍历,将节点值用逗号分隔
     * 
     * @param root BST根节点
     * @return 序列化后的字符串
     */
    public String serialize(TreeNode root) {
   
   
        if (root == null) {
   
   
            return "";
        }
        
        StringBuilder sb = new StringBuilder();
        preorder(root, sb);
        // 移除最后一个分隔符
        if (sb.length() > 0) {
   
   
            sb.setLength(sb.length() - 1);
        }
        return sb.toString();
    }
    
    /**
     * 前序遍历
     */
    private void preorder(TreeNode node, StringBuilder sb) {
   
   
        if (node == null) {
   
   
            return;
        }
        
        // 添加当前节点值
        sb.append(node.val).append(",");
        
        // 遍历左子树
        preorder(node.left, sb);
        
        // 遍历右子树
        preorder(node.right, sb);
    }
    
    /**
     * 反序列化二叉搜索树
     * 利用BST性质和前序遍历重建树
     * 
     * @param data 序列化字符串
     * @return 重建的BST根节点
     */
    public TreeNode deserialize(String data) {
   
   
        if (data == null || data.length() == 0) {
   
   
            return null;
        }
        
        // 将字符串分割为整数数组
        String[] values = data.split(",");
        int[] nums = new int[values.length];
        for (int i = 0; i < values.length; i++) {
   
   
            nums[i] = Integer.parseInt(values[i]);
        }
        
        // 使用索引数组来传递引用
        int[] index = {
   
   0};
        return buildBST(nums, index, Integer.MIN_VALUE, Integer.MAX_VALUE);
    }
    
    /**
     * 递归构建BST
     * 
     * @param nums 前序遍历的值数组
     * @param index 当前处理位置(使用数组传递引用)
     * @param min 当前子树允许的最小值
     * @param max 当前子树允许的最大值
     * @return 构建的子树根节点
     */
    private TreeNode buildBST(int[] nums, int[] index, int min, int max) {
   
   
        // 如果所有值都已处理,或当前值不在允许范围内
        if (index[0] >= nums.length || nums[index[0]] < min || nums[index[0]] > max) {
   
   
            return null;
        }
        
        // 创建根节点
        int rootVal = nums[index[0]];
        TreeNode root = new TreeNode(rootVal);
        index[0]++;  // 移动到下一个值
        
        // 递归构建左子树(值必须小于rootVal)
        root.left 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值