再刷一遍二叉树

本文详细介绍了四种二叉树操作的算法:226题的翻转二叉树、114题的二叉树展开为链表、116题的填充每个节点的下一个右侧节点指针,以及105、106题的根据遍历序列构造二叉树。每种算法都提供了清晰的递归解决方案,有助于深入理解二叉树结构及其操作。
摘要由CSDN通过智能技术生成

简单复习二叉树系列算法

(一)

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;
}



😛😛感谢看到这里,希望对理解二叉树有帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值