简单复习二叉树系列算法
文章目录
(一)
226. 翻转二叉树
226. 翻转二叉树
翻转一棵叉树。
//翻转二叉树 ✔
public TreeNode invertTree(TreeNode root){
//递归结束条件
if(root == null) return null;
//思考在此节点上要做的事
//即交换左右节点
TreeNode temp;
temp = root.left;
root.left = root.right;
root.right = temp;
//使此节点的左右子树也进行翻转
invertTree(root.left);
invertTree(root.right);
return root;
}
114. 二叉树展开为链表
114. 二叉树展开为链表
给你二叉树的根结点 root ,请你将它展开为一个单链表:
① 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
② 展开后的单链表应该与二叉树 先序遍历 顺序相同。
//二叉树展开为链表 ✔
public void flatten(TreeNode root){
if(root == null) return;
//左子树展开,右子树展开
flatten(root.left);
flatten(root.right);
//①根节点的左节点为空,②右节点为原左节点,③新右节点的最尾端接原右节点
//left,right先存一下原左右节点
TreeNode left = root.left;
TreeNode right = root.right;
//①左节点为空,②右节点为原左节点
root.left = null;
root.right = root.left;
//③新右节点的最尾端接原右节点
//找到最尾端
TreeNode p = root;
while(p.right != null){
p = p.right;
}
p.right = right;
}
116. 填充每个节点的下一个右侧节点指针
116. 填充每个节点的下一个右侧节点指针
填充二叉树的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
//填充每个节点的下一个右侧节点指针 ✔
public Node connect(Node root) {
if(root == null) return null;
//不能简单的 【root.left.next = root.right;】相连
//要考虑不在同一子树中的相邻节点的连接
//构造一个辅助函数
connectTwoNode(root.left, root.right);
return root;
}
public void connectTwoNode (Node node1. Node node2){
if(node1 == null || node2 == null) return;
node1.next = node2;
//node1的左右子节点之间相连
connectTwoNode(node1.left, node2.right);
//node1的右节点和 node2的左节点之间相连
connectTwoNode(node1.right, node2.left);
//node2的左右子节点之间相连
connectTwoNode(node2.left, node2.right);
}
(二)
654. 最大二叉树
654. 最大二叉树
给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:
① 二叉树的根是数组 nums 中的最大元素。
② 左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。
③ 右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。
//最大二叉树 ✔
public TreeNode constructMaximumBinaryTree(int[] nums) {
return build(nums, 0, nums.length-1);
}
//构造一个辅助函数,参数【数组,数组起始,数组结尾】
public TreeNode build (int[] nums, int l, int r){
//递归结束条件
if(l > r) return null;
//构造最大二叉树,二叉树的根是数组 nums 中的最大元素。
//找到根节点,构造根节点,并记录此值在数组中的位置
int maxVal = nums[l];
int index = l;
for(int i=l; i<=r; i++){
if(maxVal < nums[i]){
maxVal = nums[i];
index = i;
}
}
//构造根节点
TreeNode root = new TreeNode(maxVal);
//左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树
//右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树
//构造左、右子树
root.left = build(nums, l, index-1);
root.right = build(nums, index+1, r);
return root;
}
105. 从前序与中序遍历序列构造二叉树
105. 从前序与中序遍历序列构造二叉树
给定一棵树的前序遍历 preorder 与中序遍历 inorder。请构造二叉树并返回其根节点。
//从前序与中序遍历序列构造二叉树 ✔
public TreeNode buildTree(int[] preorder, int[] inorder){
return build(preorder, 0, preorder.length-1, inorder, 0, inorder.length-1);
}
public TreeNode build(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd){
//结束条件
if(preStart > preEnd) return null;
//二叉树的根节点是前序遍历的第一个值
//要在中序遍历中寻找到根节点的位置,以此可将序列分为左子树的序列和右子树的序列。
int rootVal = preorder[preStart];
int index = -1;
for(int i=inStart; i<=inEnd; i++){
if(inorder[i] == rootVal){
index = i;
break;
}
}
TreeNode root = new TreeNode(rootVal);
//要把前序遍历的序列也分出左右子树的序列
//设 leftSize为左子树节点个数,对前序遍历来说,【preStart+1, preStart+leftSize】即为左子树的序列。
int leftSize = index - inStart;
//构造左右子树
root.left = build(preorder, preStart+1, preStart+leftSize, inorder, inStart, index-1);
root.right = build(preorder, preStart+leftSize+1, preEnd, inorder, index+1, inEnd);
return root;
}
106. 从中序与后序遍历序列构造二叉树
106. 从中序与后序遍历序列构造二叉树
根据一棵树的中序遍历与后序遍历构造二叉树。
//从中序与后序遍历序列构造二叉树 ✔
public TreeNode buildTree(int[] inorder, int[] postorder){
return build(inorder, 0, inorder.length-1, postorder, 0, postorder.length-1);
}
public TreeNode build(int[] inorder, int inStart, int inEnd, int[] postorder, int postStart, int postEnd){
if(inStart > inEnd) return null;
//与上题相似,只是根节点为后序遍历序列的最后一个值
int rootVal = postorder[postEnd];
//中序遍历中寻找根节点
int index = -1;
for(int i=inStart; i<=inEnd; i++){
if(inorder[i] == rootVal){
index = i;
break;
}
}
TreeNode root = new TreeNode(rootVal);
int leftSize = index - inStart;
//构造左右子树
root.left = build(inorder, inStart, index-1, postorder, postStart, postStart+leftSize-1);
root.right = build(inorder, index+1, inEnd, postorder, postStart+leftSize, postEnd-1);
return root;
}
(三)
652. 寻找重复的子树
652. 寻找重复的子树
给定一棵二叉树,返回所有重复的子树。对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。
两棵树重复是指它们具有相同的结构以及相同的结点值。
//寻找重复的子树 ✔
// 用哈希表记录所有子树以及出现的次数
HashMap<String, Integer> memo = new HashMap<>();
// 以列表的形式返回上述重复子树的根结点
LinkedList<TreeNode> res = new LinkedList<>();
public List<TreeNode> findDuplicateSubtrees(TreeNode root){
findSubtrees(root);
return res;
}
public String findSubtrees(TreeNode root){
//二叉树序列化,空节点用 “#” 表示
if(root == null) return "#";
String left = findSubtrees(root.left);
String right = findSubtrees(root.right);
//序列化过程中出现的子树序列
String subTree = left + "," + right + "," + root.val;
//getOrDefault方法,获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值
int count = memo.getOrDefault(subTree, 0);
//count为 1说明有两个一样的子树,将此节点加入 res 列表中
if(count == 1) res.add(root);
//子树存入哈希表
memo.put(subTree, count+1);
return subTree;
}
😛😛感谢看到这里,希望对理解二叉树有帮助。