堆栈迭代+DFS递归 1028. 从先序遍历还原二叉树

根据先序遍历结果,利用递归DFS和迭代堆栈方法重建二叉树。递归时,全局变量i记录当前位置,判断是否能作为左子树并递归构建子树。迭代中,栈内节点数表示当前深度,新节点赋给栈顶元素。

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 之间。

递归+DFS

全局变量i记录当前遍历的位置;
(1)获取当前节点,若不能作为左子树,则还原i,返回上一层;
(2)若能做左子树,放入左子树位置;看后面是否有右子树,无则递归左子树的子树;
(3)若还有右子树,则左子树无子树,放入右子树后递归右子树的子树;

每次判断完都需要还原i;

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* recoverFromPreorder(string S) {
        if(!S.size()) return NULL;
        i=0;
        int num=cal(S);
        TreeNode * root = new TreeNode(num);
        buildtree(S,0,root);
        return root;
    }
private:
    int i;  //用于遍历字符串

    void buildtree(string S,int n,TreeNode * root){
        int cnt=0;
        int t=i;
        while(S[i]=='-'){i++; cnt++;}  //若写在while里面,非判断也会让i++
        if(cnt==n+1){      //若有左子节点
            int tmp=cal(S);
            root->left=new TreeNode(tmp);      //放入左边


            cnt=0;
            t=i;
            while(S[i]=='-') {i++;cnt++;}
            if(cnt==n+1){     //若有右子节点
                int tmp=cal(S);
                root->right=new TreeNode(tmp);  //放入右边
                buildtree(S,n+1,root->right);  //往后递归
            }else if (cnt>n+1){  //若无右子节点,但有节点
                i=t;
                buildtree(S,n+1,root->left);//往左边递归
                //左边建树完成
                cnt=0;
                t=i;
                while(S[i]=='-'){i++; cnt++;}  //检查右子树
                if(cnt==n+1){    //若有右子树
                    tmp=cal(S);
                    root->right=new TreeNode(tmp);
                    buildtree(S,n+1,root->right);  //进入右子树递归
                }else i=t;  //若无右子树
            }else i=t;
        }else i=t;
        return;
    }

    int cal(string S){
        int res=0;
        while(isdigit(S[i])){
            res=res*10+(S[i++]-'0');
        }
        return res;
    }
};

迭代+堆栈

关键点:
栈内节点数量为当前构造的深度;
每次得到新节点,赋给栈顶元素;

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* recoverFromPreorder(string S) {
        if(!S.size()) return NULL;    //确定S大小
        stack<TreeNode*> T;           //建立堆栈
        i=0;                          //从头开始遍历S
        int tmp=calnum(S);            //将根节点入栈
        TreeNode* root=new TreeNode(tmp);  
        T.push(root);                 
        while(i<S.size()){             //遍历S
            int len=calflr(S);        //计算当前节点深度
            int num=calnum(S);         //计算当前节点数值
            TreeNode * newnode=new TreeNode(num);   //构造当前节点
            while(len<T.size()) T.pop();   //若当前节点深度小于栈内节点数量,栈内节点出栈
            TreeNode * temp=T.top();       //取出栈顶元素
            if(!temp->left) temp->left=newnode;   //先判断栈顶元素有无左子树,无则赋值
            else temp->right=newnode;       //有则右子树赋值
            T.push(newnode);                //新节点入队
        }
        return root;
    }
private:
    int i;
    int calnum(string S){
        int res=0;
        while(isdigit(S[i]))    res=res*10+S[i++]-'0';
        return res;
    }

    int calflr(string S){
        int cnt=0;
        while(i<S.size()&&S[i]=='-') {i++;cnt++;}
        return cnt;
    }
};
### 二叉树深度优先搜索(DFS遍历 #### 概述 深度优先搜索(Depth First Search, DFS)是一种用于遍历或搜索或图的算法。对于二叉树而言,其特点在于尽可能深地探索每一个分支[^1]。 #### 基本原理 深度优先搜索通常可以通过递归或者显式的来实现。它的核心思想是从根节点出发,沿着某个路径一直向下访问子节点直到无法继续为止,然后再回溯到上一层并重复这一过程。 #### 实现方式 以下是两种常见的实现方法: ##### 方法一:递归实现 递归是最直观的方式之一,它利用函数调用堆栈自然模拟了深度优先的行为。下面是一个基于 Java 的后序遍历示例代码[^2]: ```java class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } import java.util.ArrayList; import java.util.List; public class Solution { public List<Integer> postorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); postorder(root, result); return result; } private void postorder(TreeNode node, List<Integer> result) { if (node == null) return; postorder(node.left, result); // 访问左子 postorder(node.right, result); // 访问右子 result.add(node.val); // 处理当前节点 } } ``` 上述代码展示了如何通过递归来完成二叉树的后序遍历操作。注意,在其他类型的遍历时只需要调整 `postorder` 函数中的三行语句顺序即可适应前序和中序的需求。 ##### 方法二:迭代实现(使用显式) 当不希望采用递归形式时,则可以借助额外的数据结构——来进行手动管理。这里给出一个通用框架以及具体针对后续遍历的例子: ```java import java.util.Stack; public List<Integer> postOrderIterative(TreeNode root){ Stack<TreeNode> stack = new Stack<>(); List<Integer> resultList = new ArrayList<>(); if (root == null) return resultList; TreeNode prev = null; stack.push(root); while (!stack.isEmpty()) { TreeNode current = stack.peek(); /* go down the tree in search of a leaf an if so process it and pop * stack otherwise move down */ if ((current.left == null && current.right == null) || (prev != null && (prev == current.left || prev == current.right))) { resultList.add(current.val); stack.pop(); prev = current; } else { if (current.right != null) stack.push(current.right); if (current.left != null) stack.push(current.left); } } return resultList; } ``` 此版本避免了潜在的因过深递归而导致溢出的风险,并且同样适用于不同种类的遍历模式只需稍作修改逻辑部分即可。 #### 总结 无论是采取递归还是非递归的形式,只要遵循先处理一侧再转向另一侧的原则就能正确执行整个流程。每种策略都有各自适用场景与优缺点需视具体情况选择最合适的方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值