题目说明
我们从二叉树的根节点 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]
提示:
原始树中的节点数介于 1 和 1000 之间。
每个节点的值介于 1 和 10 ^ 9 之间。
解题思路一(S转换数组,前序特性分割递归)
- 这道题是困难题,但是其实对二叉树稍微熟悉点的话,并不是很难,只能说麻烦一些,一共分两步,第一步处理字符串,第二步构建二叉树。
- 第一步首先将
"1-401--349---90--88"
转换成一个同顺序的节点数组arr
,这样便于我们操作。
- 第二步构建二叉树
- 首先选择根节点,也就是
arr
的第一位,其level
为0
。
- 然后在
arr.slice(1)
中寻找level
为1
的节点,也就是root
的left
和right
节点。
- 注意题目说明:如果节点只有一个子节点,那么保证该子节点为左子节点。
- 也就是说我们按顺序遍历
arr
,第一个level
为1
的就是root
的left
节点,第二个就是right
节点(最多两个)
- 当找到
left
节点时,声明left
变量记录下标i
,right
节点同样记录下标,搜索完毕之后level++
[left+1,right)
为左树节点数组,[right + 1,arr.length)
为右树节点,分割递归。
- 然后判读root.left 是否存在,若存在
root.left && build(root.left, arr.slice(left + 1, right), level);
- 然后判读root.right 是否存在,若存在
root.right && build(root.right , arr.slice(right + 1), level);
- 当数组为空时返回。
- 返回root
代码实现一
var recoverFromPreorder = function(S) {
let levelFlag = 0;
let arr = [];
let num = '';
for (let i = 0; i < S.length; i++) {
if (S[i] === '-') {
levelFlag++;
} else {
num += S[i];
if (S[i + 1] == '-' || (i + 1) == S.length) {
let node = new TreeNode(num);
node.level = levelFlag;
arr.push(node)
levelFlag = 0;
num = '';
}
}
}
let root = arr[0];
build(root, arr.slice(1), 1);
return root;
};
var build = function(root, arr, level) {
if (!arr.length) {
return;
}
let left = 0;
let right = arr.length;
for (let i = 0; i < arr.length; i++) {
if (arr[i].level === level) {
if (root.left == null) {
root.left = arr[i];
left = i;
} else {
root.right = arr[i];
right = i;
break;
}
}
}
level++;
root.left && build(root.left, arr.slice(left + 1, right), level);
root.right && build(root.right, arr.slice(right + 1), level);
}