“Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。”
一、题目描述:
606. 根据二叉树创建字符串
你需要采用前序遍历的方式,将一个二叉树转换成一个由括号和整数组成的字符串。
空节点则用一对空括号 "()" 表示。而且你需要省略所有不影响字符串与原始二叉树之间的一对一映射关系的空括号对。
示例 1:
输入: 二叉树: [1,2,3,4]
1
/ \
2 3
/
4
输出: "1(2(4))(3)"
解释: 原本将是“1(2(4)())(3())”,
在你省略所有不必要的空括号对之后,
它将是“1(2(4))(3)”。
示例 2:
输入: 二叉树: [1,2,3,null,4]
1
/ \
2 3
\
4
输出: "1(2()(4))(3)"
解释: 和第一个示例相似,
除了我们不能省略第一个对括号来中断输入和输出之间的一对一映射关系。
二、思路分析及代码:
我们要通过二叉树先序遍历来生成括号和数值组合的字符串,显然有递归和迭代两种方法。
但我们先根据题目得出加入值的种类,节点为空 根据题目:若是根节点返回"",否则是(),而且对于一个子树上的左右子树都要用()包裹左右子树中的的值,值()不必变成(())。并且题目要求去除无意义的括号例如对于二叉树[1],表示为1,而不是1()()
分析遍历过程中,会遇到的不同情况,以此来除去空格,我们假设当前结点node不为空,结果已经加上node.val的值
- 首先,当结点孩子都为空,我们不做任何操作即可,否则会生成多余的()
- 当结点只有右孩子为空时,我们不遍历它即可,即结果加上 (change(node.left)),避免无意义()
- 当结点只有左孩子为空时,这个()不能省略,故结果加上()+(change(node.right))
- 结点都不为空时,都遍历即可,即(change(node.left))+(change(node.right))
现在只剩下一个难点,就是各个子树根节点的()如何加上,对于根节点来说,不需要(),对于其他结点首先(然后遍历子树结束再加上)。递归和迭代的实现过程不同
- 递归
const change=function(node){
if(node===null){
return ""
}
if(node.left===null&&node.right===null){
return node.val+"" ;
}
if(node.right===null){
return node.val+"("+change(node.left)+")"
}
return node.val+"("+change(node.left)+")"+"("+change(node.right)+")"
}
递归的实现过程为递归子节点前就加上相应的括号
- 迭代
/**
* @param {TreeNode} root
* @return {string}
*/
var tree2str = function(root) {
if(root===null)return ''
let nodes=[root]
let ans=''
let via=new Set()
while(nodes.length){
let node=nodes[nodes.length-1]
if(via.has(node)){
if(node!==root)
ans+=")"
nodes.pop()
}else{
if(node!=root)
ans+="("
ans+=node.val
via.add(node)
if(!node.left&&!node.right)continue
if(!node.left&&node.right){
ans+="()"
}
if(node.right)nodes.push(node.right)
if(node.left)nodes.push(node.left)
}
}
return ans
};
而对于迭代,需要用nodes存储遍历的节点,用一个set集合判断当前节点是否遍历完成。当结点为遍历时若不为root则需加上(,同样遍历完成时不为根节点需加上)这样才能避免无意义括号