之前在力扣刷二叉树类型的题目时,经常会遇到bug,代码的结果和自己的预期不符,此时想到本地调试,却要先构造一个二叉树作为输入。之前一直用的笨方法,就是一个个new节点,然后把指针连起来。如果运气不好,这棵树运行成功了,又卡在另一棵树上,又要重新构造一棵树,很麻烦,导致我想放弃调试了。在网上也没有找到相关的转换代码,正好前几天做到 二叉树的序列化与反序列化 这道题,发现刚好和这个需求匹配。
废话不多说,直接上代码,可以拿去直接用。
/**
* 二叉树调试工具类
* 根据层次遍历的二叉树字符串形式构造二叉树
*/
class TreeUtils {
// 分隔符
String SEP = ",";
// 空值
String NULL = "null";
/* 将字符串反序列化为二叉树结构 */
TreeNode buildTree(String data) {
if (data.isEmpty()) return null;
// 去除首位"[", "]"
data = data.substring(1,data.length()-1);
// 在data后加若干个空值
for(int i = 0; i < 100; i++) data += SEP + NULL;
String[] nodes = data.split(SEP);
// 第一个元素就是 root 的值
TreeNode root = new TreeNode(Integer.parseInt(nodes[0]));
// 队列 q 记录父节点,将 root 加入队列
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
for (int i = 1; i < nodes.length; ) {
// 队列中存的都是父节点
TreeNode parent = q.poll();
if(parent == null) break;
// 父节点对应的左侧子节点的值
String left = nodes[i++];
if (!left.equals(NULL)) {
parent.left = new TreeNode(Integer.parseInt(left));
q.offer(parent.left);
} else {
parent.left = null;
}
// 父节点对应的右侧子节点的值
String right = nodes[i++];
if (!right.equals(NULL)) {
parent.right = new TreeNode(Integer.parseInt(right));
q.offer(parent.right);
} else {
parent.right = null;
}
}
return root;
}
}
比如,我今天做 652. 寻找重复的子树 这道题的时候,遇到bug,想在本地调试自己的代码,因此我需要用上述工具类构造出我没过的那个二叉树,再一步步调试我的代码。
比如,想构造下图所示二叉树
本地调试代码如下
Main.java
public class Main {
public static void main(String[] args) {
// 自己的解法
Solution s = new Solution();
// 构造二叉树工具类
TreeUtils treeUtils = new TreeUtils();
// 将力扣的二叉树输入复制过来作为构造二叉树的参数
TreeNode root = treeUtils.buildTree("[1,2,3,4,null,2,4,null,null,4]");
// 将构造好的二叉树作为解法参数传入,调试自己的代码
List<TreeNode> duplicateSubtrees = s.findDuplicateSubtrees(root);
// 查看输出
System.out.println(duplicateSubtrees);
return;
}
}
Solution.java
// Definition for a binary tree node.
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 TreeUtils {
// 分隔符
String SEP = ",";
// 空值
String NULL = "null";
/* 将字符串反序列化为二叉树结构 */
TreeNode buildTree(String data) {
if (data.isEmpty()) return null;
// 去除首位"[", "]"
data = data.substring(1,data.length()-1);
// 在data后加若干个空值
for(int i = 0; i < 100; i++) data += SEP + NULL;
String[] nodes = data.split(SEP);
// 第一个元素就是 root 的值
TreeNode root = new TreeNode(Integer.parseInt(nodes[0]));
// 队列 q 记录父节点,将 root 加入队列
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
for (int i = 1; i < nodes.length; ) {
// 队列中存的都是父节点
TreeNode parent = q.poll();
if(parent == null) break;
// 父节点对应的左侧子节点的值
String left = nodes[i++];
if (!left.equals(NULL)) {
parent.left = new TreeNode(Integer.parseInt(left));
q.offer(parent.left);
} else {
parent.left = null;
}
// 父节点对应的右侧子节点的值
String right = nodes[i++];
if (!right.equals(NULL)) {
parent.right = new TreeNode(Integer.parseInt(right));
q.offer(parent.right);
} else {
parent.right = null;
}
}
return root;
}
}
// 652. 寻找重复的子树
class Solution {
List<TreeNode> res = new LinkedList<>();
HashMap<String, Integer> map = new HashMap<>();
public List<TreeNode> findDuplicateSubtrees(TreeNode root) {
traverse(root);
return res;
}
String traverse(TreeNode root){
if(root == null) return "#";
String left = traverse(root.left);
String right = traverse(root.right);
String rootStr = left + "," + right + "," + root.val;
if(map.getOrDefault(rootStr, 0) == 1){
res.add(root);
}
map.put(rootStr, map.getOrDefault(rootStr, 0) + 1);
return rootStr;
}
}
主体代码参考东哥的东哥带你刷二叉树(序列化篇)
主要是借鉴用层次遍历解决二叉树的序列化与反序列化的思路,但有一点改变。
null
值的,类似完全二叉树null
值,类似满二叉树举个例子
在 652. 寻找重复的子树 题目中的示例,力扣给出的二叉树输入形式如下图所示
而层次遍历反序列化二叉树的输入形式应该如下图所示
输入: root = [1,2,3,4,null,2,4,null,null,4,null,null,null]
解决办法也很容易,就是在力扣的输入后面加若干个null
值
// 在data后加若干个空值
for(int i = 0; i < 100; i++) data += SEP + NULL;
工具类中已经解决,直接复制力扣的输入即可。
东哥带你刷二叉树(序列化篇)