【每日一题】LeetCode. 1028. 从先序遍历还原二叉树

每日一题,防止痴呆 = =

一、题目大意

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

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

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

给出遍历输出 S,还原树并返回其根节点 root。
在这里插入图片描述
在这里插入图片描述
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/recover-a-tree-from-preorder-traversal

二、题目思路以及AC代码

思路

对于普通的先序遍历,我们知道是无法还原成唯一的二叉树的,但是本题给了每个节点的深度,同时规定如果某个节点只有一个子节点,那么该子节点一定是左子节点,这也就使得这种先序遍历是可以唯一表达一棵二叉树的。

思路其实同先序和中序恢复二叉树类似,肯定是用递归来实现。我们可以先把题目给定的先序序列处理一下,比如 “1-2–3--4-5–6--7”,我们可以将其处理为一个值数组和一个深度数组,并且一一对应,也就是 val: [1, 2, 3, 4, 5, 6, 7]; depth: [0, 1, 2, 2, 1, 2, 2]。

这样我们在每次递归时,只要找到当前节点两个子节点在数组中的位置,其中左子节点的位置肯定是 l+1,所以我们只需要找右子节点的位置即可,然后对左右两个序列继续递归,将递归结果作为左右指针赋值给当前节点的左右子树,具体可以参见代码。

AC代码
/**
 * 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 {
private:
    vector<int> val;
    vector<int> depth;
public:
    TreeNode* recoverTree(int l, int r) {
        if (l > r) return NULL;

        TreeNode* root = new TreeNode(val[l]);
        int d = depth[l];

        int left = l + 1, right = r + 1;
        if (left > r) return root;
        for (int i=left + 1;i<=r;i++) {
            if (depth[i] == d+1) {
                right = i;
                break;
            }
        }

        root->left = recoverTree(left, right - 1);
        root->right = recoverTree(right, r);

        return root;
    }

    TreeNode* recoverFromPreorder(string S) {
        int len = S.length();

        int i = 0;
        while (i < len) {
            // 找 - 
            int cnt = 0;
            while (i < len && S[i] == '-') {
                i++;
                cnt++;
            }

            string tmp = "";
            while (i < len && S[i] != '-') {
                tmp += S[i++];
            }

            int value = atoi(tmp.c_str());

            val.push_back(value);
            depth.push_back(cnt);
        }

        return recoverTree(0, val.size() - 1);
    }   
};

如果有问题,欢迎大家指正!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值