labuladong算法公众号学习笔记
根据题意,思考一个二叉树节点需要做什么,到底用什么遍历就清楚了
二叉树框架
void traverse(TreeNode root){
//前序遍历
traverse(root.left);
//中序遍历
traverse(root.right);
//后序遍历
}
节点应该做什么
- 以自己为根的二叉树(子树)是什么样子
- 以其他节点为根的子树的样子
如何知道自己的子树
用后序遍历法,要先知道自己的左子树、右子树和根才行。
举例:二叉树有多少节点:
int count(TreeNode root){
if(root == null) return 0;
//先计算出左右子树有多少节点
int left=count(root.left);
int right=count(root.right);
/*后序遍历代码*/
int res=left+right+1;
return res;
}
例:通过拼接字符串的方式把二叉树序列化
String traverse(TreeNode root){
//空节点,可以用一个特殊字符表示
if(root == null) return "#";
String left = traverse(root.left);
String right = traverse(root.right);
/*后序遍历代码*/
//左右子树加上自己,就是以自己为根的二叉树
String subTree = left +" "+ right;
return subTree;
}
知道别的树长什么样
可以借助一个外部数据结构,让每个节点把自己子树的序列化结果存进去,这样,对于每个节点,可以知道其他节点的子树和自己是否重复。
可以利用HashMap来额外记录每棵子树的出现次数:
//记录所有子数以及出现的次数
HashMap<String,Integer> memo = new HashMap<>();
//记录重复的子树根节点
LinkedList<TreeNode> res = new LinkedList<>();
/*主函数*/
List<TreeNode> findDuplicatedSubtree(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 subTree = left + " , " + right;
int freq = memo.getOrDefault(subTree,0);
//多次重复也只会被加入结果集一次
if(freq == 1) res.add(root);
//给子树对应的出现次数加1
memo.put(subTree,freq+1);
return subTree;
}