20200618
题目(难度:困难):
我们从二叉树的根节点 root 开始进行深度优先搜索。
在遍历中的每个节点处,我们输出 D 条短划线(其中 D 是该节点的深度),然后输出该节点的值。(如果节点的深度为 D,则其直接子节点的深度为 D + 1。根节点的深度为 0)。
如果节点只有一个子节点,那么保证该子节点为左子节点。
给出遍历输出 S,还原树并返回其根节点 root。
示例
- 示例 1
1
/ \
2 3
/ \ / \
4 5 6 7
输入:"1-2--3--4-5--6--7"
输出:[1,2,5,3,4,6,7]
- 示例 2
1
/ \
2 5
/ /
3 6
/ /
4 7
输入:"1-2--3---4-5--6---7"
输出:[1,2,5,3,null,6,null,4,null,7]
- 示例 3
1
/
401
/ \
349 88
/
90
输入:"1-401--349---90--88"
输出:[1,401,null,349,88,90]
提示
- 原始树中的节点数介于 1 和 1000 之间。
- 每个节点的值介于 1 和 10 ^ 9 之间。
抛砖引玉
- 输入一个字符串
- 字符串中n个’-'表示n级
- '—n…—m’表示n和m都是上一级的子集,n是left,m是right,先left后right
- 字符串顺序:一条线所有的子节点+下一条线所有子节点…
逻辑
- 先取出第一个数组作为树的根节点
- 循环字符串记录’-'的个数,多少个n就记录多少级,根据级数把能得到的树放到数组中
- 记录level和取本层数据的注意事项:
- 数字和’-'切换时重置level和value
- 因为字符串顺序:一条线所有的子节点+下一条线所有子节点…,以第二层为例:
- 第一条线循环到结束后可能还会在之后一个有level为2的数据,
- 那就可以判断这个level是不是已经有了left、right没有的话就给员树增加新的树节点
- 依次类推,所有后面出现的节点本身都是有依附节点的,最终所有的节点都会追加到起始的根节点
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {string} S
* @return {TreeNode}
*/
var recoverFromPreorder = function (S) {
var level = 0,
value = 0
var _result = [new TreeNode(S.split('-')[0])]
for (let i = 1; i < S.length; i++) {
if (S[i] == '-') {
level++
value = 0
} else if (level > 0) {
value = value * 10 + Number(S[i])
if ((S[i + 1] && S[i + 1] === '-') || i === S.length - 1) {
var nodeTree = new TreeNode(value)
if (_result[level - 1].left == null) {
_result[level - 1].left = nodeTree
} else {
_result[level - 1].right = nodeTree
}
_result[level] = nodeTree
level = 0
}
}
}
return _result[0]
}
其他解法
/**
* @param {number[]} A
* @return {number}
*/
var recoverFromPreorder = function (S) {
const stack = []
for (let i = 0; i < S.length;) {
let curLevel = 0 //一个curNode对应一个curLevel
while (i < S.length && S[i] == '-') { // 避免循环半途中出界
i++
curLevel++ // 连字符个数代表level
}
const start = i // 记录当前节点值的开始位置
while (i < S.length && S[i] != '-') {
i++ // 指针移到当前节点值的结束位置
}
const curNode = new TreeNode(S.slice(start, i)) //创建当前节点
if (stack.length == 0) { // ROOT入栈,不用找父亲,continue
stack.push(curNode)
continue
}
while (stack.length > curLevel) { // 栈顶不是父亲,栈顶出栈
stack.pop() // 直到栈顶是父亲
}
if (stack[stack.length - 1].left) { // 左儿子已存在
stack[stack.length - 1].right = curNode // 安排为右儿子
} else {
stack[stack.length - 1].left = curNode // 安排为左儿子
}
stack.push(curNode) // 节点肯定要入栈一次
}
return stack[0] // 栈底就是根节点
};
- 使用递归,一个层级一次递归
- 使用正则切分除本层的数据和未分离出来的字符串
- 本层数据直接生成树结构
- 未分离的数据根据切位的位置,递归进入left和right
/**
* @param {number[]} A
* @return {number}
*/
var maxScoreSightseeingPair = function (A) {
if (!S) return null
const reg = new RegExp(`(?<=\\d)${char}(?=\\d)`),
[root, left, right] = S.split(reg),
treeNode = new TreeNode(+root);
treeNode.left = recoverFromPreorder(left, char + '-')
treeNode.right = recoverFromPreorder(right, char + '-')
return treeNode
}
菜鸟的自白
- 开始的思路也是通过正则匹配出来,但是对数据的切分一直错误,才不得不去按部就班的去循环,个人觉得,正则出来起来会更简洁
// 配置 两个数字包含着的层级数[val-left,*-right]
/\d-{n}\d/g
// 跟 数字 -- 数字 切分字符串
/?<=\\d)${char}(?=\\d/g
博客: 小书童博客(http://gaowenju.com)
公号: 坑人的小书童