[LeetCode]1028. 从先序遍历还原二叉树

题目

我们从二叉树的根节点 root 开始进行深度优先搜索。

在遍历中的每个节点处,我们输出 D 条短划线(其中 D 是该节点的深度),然后输出该节点的值。(如果节点的深度为 D,则其直接子节点的深度为 D + 1。根节点的深度为 0)。

如果节点只有一个子节点,那么保证该子节点为左子节点。

给出遍历输出 S,还原树并返回其根节点 root

示例 1:
在这里插入图片描述

输入:"1-2--3--4-5--6--7"
输出:[1,2,5,3,4,6,7]

示例 2:
在这里插入图片描述

输入:"1-2--3---4-5--6---7"
输出:[1,2,5,3,null,6,null,4,null,7]

示例 3:
在这里插入图片描述

输入:"1-401--349---90--88"
输出:[1,401,null,349,88,90]

提示:

  • 原始树中的节点数介于 11000 之间。
  • 每个节点的值介于 110 ^ 9 之间。

解题思路

记当前节点为 T,上一个节点为 S,那么实际上只有两种情况:
1)T 是 S 的左子节点;
2)T 是根节点到 S 这一条路径上(不包括 S)某一个节点的右子节点。
为什么不包括 S?因为题目中规定了如果节点只有一个子节点,那么保证该子节点为左子节点。在 T 出现之前,S 仍然还是一个叶节点,没有左子节点,因此 T 如果是 S 的子节点,一定是优先变成 S 的左子节点。

对于在先序遍历中任意的两个相邻的节点 S 和 T,要么 T 是 S 的左子节点(对应上面的第一种情况),要么在遍历到 S 之后发现 S 是个叶节点,于是回溯到之前的某个节点,并开始递归地遍历其右子节点(对应上面的第二种情况)。

当得到当前节点的值以及深度信息之后,可以发现:如果 T 是 S 的左子节点,那么 T 的深度恰好比 S 的深度大 1;在其它的情况下,T 是栈中某个节点(不包括 S)的右子节点,那么我们将栈顶的节点不断地出栈,直到 T 的深度恰好比栈顶节点的深度大 1,此时我们就找到了 T 的父节点。

复杂度分析:
时间复杂度:O(|s|),其中 |s| 是字符串 S 的长度。我们的算法不断地从 S 中取出一个节点的信息,直到取完为止。在这个过程中,我们实际上是对 S 进行了一次遍历。
时间复杂度:O(h),其中 h 是还原出的二叉树的高度。除了作为答案返回的二叉树使用的空间以外,我们使用了一个栈帮助我们进行迭代。由于栈中存放了从根节点到当前节点这一路径上的所有节点,因此最多会有 h 个节点。

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode recoverFromPreorder(String S) {
        Deque<TreeNode> stack = new LinkedList<>();
        int i = 0;
        while(i<S.length()){
            int level = 0;
            // 如果遇见的是字符 ‘-’,继续向后遍历
            while(S.charAt(i) == '-'){
                i++; // 字符索引
                level++; // 节点深度
            }
            int value = 0;
            // 如果是数字
            while(i<S.length() && Character.isDigit(S.charAt(i))){
                value = value*10 + S.charAt(i) - '0';
                i++;
            }
            TreeNode cur = new TreeNode(value);
            // 如果当前深度等于栈的深度且栈非空,表示当前节点是栈顶节点的左孩子
            if(level == stack.size()){
                // 根节点没有父节点,要进行一次非空的判断
                if(!stack.isEmpty()){
                    TreeNode node = stack.peek();
                    node.left = cur;
                }
                // TreeNode node = stack.peek();
                // node.left = cur;
            }else{
                while(level != stack.size()){
                    stack.pop();
                }
                TreeNode node = stack.peek();
                node.right = cur;
            }
            stack.push(cur);
        }
        while(stack.size()>1){
            stack.pop();
        }
        TreeNode root = stack.peek();
        return root;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值