Given the root
of a binary tree, construct a string consisting of parenthesis and integers from a binary tree with the preorder traversal way, and return it.
Omit all the empty parenthesis pairs that do not affect the one-to-one mapping relationship between the string and the original binary tree.
Example 1:
Input: root = [1,2,3,4] Output: "1(2(4))(3)" Explanation: Originally, it needs to be "1(2(4)())(3()())", but you need to omit all the unnecessary empty parenthesis pairs. And it will be "1(2(4))(3)"
Example 2:
Input: root = [1,2,3,null,4] Output: "1(2()(4))(3)" Explanation: Almost the same as the first example, except we cannot omit the first parenthesis pair to break the one-to-one mapping relationship between the input and the output.
Constraints:
- The number of nodes in the tree is in the range
[1, 104]
. -1000 <= Node.val <= 1000
本质就是preorder,只是在打印每个node的时候,把它的child都放进括号里。如果是有left没有right就不用给right一个空括号;但如果有right没有left就要给left一个空括号占个位置。
递归的写法还挺容易
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public String tree2str(TreeNode root) {
StringBuilder sb = new StringBuilder();
preorder(root, sb);
return sb.toString();
}
private void preorder(TreeNode root, StringBuilder sb) {
sb.append(root.val);
if (root.left != null) {
sb.append("(");
preorder(root.left, sb);
sb.append(")");
}
if (root.right != null) {
if (root.left == null) {
sb.append("()");
}
sb.append("(");
preorder(root.right, sb);
sb.append(")");
}
}
}
迭代,不小心提前被剧透了需要用到额外set,就自己写了个80%。然而没想到的点就是可以每次在sb.append(node.va)的时候按"(" + node.val来append,而不用node.val + "(",这样就无脑很多,不需要考虑那么多情况,最后return的时候substring一下就完事了。
其实跟preorder的迭代一样,但是需要用到额外的seen set来判断这个node是否已经遍历过了,这个其实很容易想到,因为要给string加后括号相当于是要有回溯的思想在里面。自己写的时候因为是边想边写的,所以把有没有左右的情况分的很清楚,其实可以更优化的:我们只需要考虑在node被peek的时候无脑"(" + node.val,被pop的时候无脑")",其他时候就只有当left == null && right != null的时候加个"()"就行了。
自己写的:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public String tree2str(TreeNode root) {
StringBuilder sb = new StringBuilder();
Deque<TreeNode> stack = new ArrayDeque<>();
Set<TreeNode> seen = new HashSet<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.peek();
if (!seen.contains(node)) {
sb.append("(" + node.val);
seen.add(node);
if (node.left != null && node.right != null) {
stack.push(node.right);
stack.push(node.left);
} else if (node.left == null && node.right == null) {
sb.append(")");
} else if (node.left == null && node.right != null) {
sb.append("()");
stack.push(node.right);
} else {
stack.push(node.left);
}
} else {
node = stack.pop();
if (node.left != null || node.right != null) {
sb.append(")");
}
}
}
return sb.substring(1, sb.length() - 1).toString();
}
}
优化版,其实不仅代码简洁,速度也快了不少。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public String tree2str(TreeNode root) {
StringBuilder sb = new StringBuilder();
Deque<TreeNode> stack = new ArrayDeque<>();
Set<TreeNode> seen = new HashSet<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.peek();
if (!seen.contains(node)) {
sb.append("(" + node.val);
seen.add(node);
if (node.right != null && node.left == null) {
sb.append("()");
}
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
} else {
node = stack.pop();
sb.append(")");
}
}
return sb.substring(1, sb.length() - 1).toString();
}
}
然后还看到了一种不需要用visited set的,采用dummy node。因为一个前括号总会搭配一个后括号,并且后括号应该在遍历完左右子树以后才出现,于是我们可以每次pop一个node的时候就先push一个dummy node。如果pop到的是dummy node就给它加个后括号。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public String tree2str(TreeNode root) {
StringBuilder sb = new StringBuilder();
Deque<TreeNode> stack = new ArrayDeque<>();
TreeNode dummy = new TreeNode();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
if (node == dummy) {
sb.append(")");
} else {
sb.append("(" + node.val);
stack.push(dummy);
if (node.right != null && node.left == null) {
sb.append("()");
}
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
}
return sb.substring(1, sb.length() - 1).toString();
}
}