注:这类题目最基本的解题思路是利用递归分治 (也可以使用迭代方法),在构建树结构的时候,我们通常会使用前序遍历的思路自上而下,进行建树,每一次递归中,得到左右子树的值进行连接。
Leetcode 114 - Flatten Binary Tree to LinkedList
LeetCode 426 - Convert BST to Sorted Doubly Linked List
Leetcode 297. 序列化和反序列化二叉树
Leetcode 106. Construct Binary Tree from Inorder and Postorder Traversal
Leetcode 105. Construct Binary Tree from Preorder and Inorder Traversal
Leetcode 536. Construct Binary Tree from String
Leetcode 606. Construct String from Binary Tree
Leetcode 889. Construct Binary Tree from Preorder and Postorder Traversal
Leetcode 449. Serialize and Deserialize BST
将二叉树以前序遍历的顺序转化成连接结构,要求in-place即不占用额外空间存储新的链表结构。基本思路是递归分治,这里我们使用后序遍历的思路,先拿到左右结点然后转化成链表结构,在每一次递归中:
class Solution {
public void flatten(TreeNode root) {
dfs(root);
}
private void dfs(TreeNode root) {
if (root==null) return;
if (root.left==null && root.right==null) return;
dfs(root.left);
dfs(root.right);
if (root.left==null) return;
else {
TreeNode dum = root.left;
while (dum.right!=null) {
dum = dum.right;
}
dum.right = root.right;
root.right = root.left;
root.left = null;
}
}
}
二叉树序列化问题,根据二叉树前序遍历顺序将各节点按照继承关系打印出来
例子:[1,2,3,4] -> "1(2(4))(3)"
二叉树序列化,通常思路就是前序遍历依次打印各个节点,按照分治的思路,我们在每一次递归任务中,需要做以下步骤:
代码如下:
时间复杂度: ; 空间复杂度: , h代表递归深度。
class Solution {
StringBuilder str = new StringBuilder();
public String tree2str(TreeNode root) {
dfs(root);
return str.toString();
}
private void dfs(TreeNode root) {
if (root==null) return;
str.append(root.val+"");
if (root.left==null && root.right==null) return;
str.append('(');
dfs(root.left);
str.append(')');
// skip if right == null
if (root.right!=null) {
str.append('(');
dfs(root.right);
str.append(')');
}
}
}
这道题目则是上面LC.606的反序列化,通过给定序列化字符串构造原始的树结构,由于序列化后可以通过"()" 来判断节点的父子关系,这道题思路有一些类似Leetcode基础计算器或者表达式计算的问题,我们需要维护一个栈结构,在遍历字符串过程中:
代码如下:
时间复杂度: ; 空间复杂度: , h代表递归深度。
class Solution {
public TreeNode str2tree(String s) {
if (s==null || s.length()==0) return null;
Stack stk = new Stack<>();
for (int i=0; i='0' && s.charAt(i)<='9') || s.charAt(i)=='-')) {
num+=s.charAt(i);
i++;
}
TreeNode node = new TreeNode(Integer.parseInt(num));
stk.push(node);
}
}
return stk.pop();
}
}
上面两道题目的合并版,比起使用上述括号形式进行序列化编码,这道题目我们可以对于序列化的格式进行简化,对于缺失的左右叶子结点我们用NULL来表示,每一个结点以逗号隔开。
对于反序列化的步骤,由于序列化是以前序遍历的顺序,所以反序列化也利用前序遍历的顺序,每一次递归过程中进行如下操作:
前序遍历的特性是根-左-右,是比较适合构建二叉树这类问题
代码如下:
public class Codec {
StringBuilder str;
// Encodes a tree to a single string.
public String serialize(TreeNode root) {
str = new StringBuilder();
helper(root);
return str.toString().substring(0, str.length()-1);
}
private void helper(TreeNode root) {
if (root==null) {
str.append("null,");
return;
}
str.append(root.val+",");
helper(root.left);
helper(root.right);
}
// Decodes your encoded data to tree.
public TreeNode deserialize(String data) {
List nodes = new LinkedList(Arrays.asList(data.split(",")));
return deshelper(nodes);
}
private TreeNode deshelper(List nodes) {
if (nodes==null || nodes.size()==0) return null;
if (nodes.get(0).equals("null")) {
nodes.remove(0);
return null;
}
TreeNode curr = new TreeNode(Integer.parseInt(nodes.get(0)));
nodes.remove(0);
curr.left = deshelper(nodes);
curr.right = deshelper(nodes);
return curr;
}
}