本次题目
- 106 从中序与后序遍历序列构造二叉树
- 105 从前序与中序遍历序列构造二叉树
- 654 最大二叉树
- 617 合并二叉树
106 从中序与后序遍历序列构造二叉树
- 递归:
- 输入两个数组及其起始终止位置(减少定义新数组的次数,提高效率)。
- 若数组不为空(节点不为空),则取后序数组的最后一个节点(根节点)为中序数组的切割点,将中序数组分为左右两部分。
- 再根据中序数组的左右两部分切割后序数组为左右两部分,递归处理他们两个的左右部分。
- 注意:切割时建议左闭右开,中序数组左右部分之间有一个切割点不能取,但是后序数组左右两部分之间没有切割点,后序数组的切割点在最后,因此最后一个不能取。
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
//初始化,输入两个数组及其起始终止位置(减少定义新数组的次数,提高效率)
//左闭右开
return buildTreeInPost(inorder, 0, inorder.length, postorder, 0, postorder.length);
}
//递归函数
public TreeNode buildTreeInPost(int[] inorder, int inLeft, int inRight, int[] postorder, int postLeft, int postRight){
//如果数组为空,直接返回
if(inRight - inLeft < 1) return null;
//只有一个元素
if(inRight - inLeft == 1) return new TreeNode(inorder[inLeft]);
//若数组不为空(节点不为空),则取后序数组的最后一个节点(根节点)为中序数组的切割点
int val = postorder[postRight - 1];
TreeNode root = new TreeNode(val);
int inCut = 0;
for(int i = inLeft; i < inRight; i++){
if(inorder[i] == val){
inCut = i;
break;
}
}
//再根据中序数组的左右两部分(个数)切割后序数组为左右两部分
//递归处理他们两个的左右部分
//左闭右开
//中序数组左右部分之间有一个切割点不能取
//但是后序数组左右两部分之间没有切割点,后序数组的切割点在最后,因此最后一个不能取
root.left = buildTreeInPost(inorder, inLeft, inCut, postorder, postLeft, postLeft + (inCut - inLeft));
root.right = buildTreeInPost(inorder, inCut + 1, inRight, postorder, postLeft + (inCut - inLeft), postRight - 1);
//返回结果
return root;
}
}
105 从前序与中序遍历序列构造二叉树
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
//初始化,输入两个数组及其起始终止位置(减少定义新数组的次数,提高效率)
//左闭右开
return buildTreePreIn(preorder, 0, preorder.length, inorder, 0, inorder.length);
}
//递归函数
public TreeNode buildTreePreIn(int[] preorder, int preLeft, int preRight, int[] inorder, int inLeft, int inRight){
//如果数组为空,直接返回
if(inRight - inLeft < 1) return null;
//只有一个元素
if(inRight - inLeft == 1) return new TreeNode(inorder[inLeft]);
//若数组不为空(节点不为空),则取前序数组的第一个节点(根节点)为中序数组的切割点
int val = preorder[preLeft];
TreeNode root = new TreeNode(val);
int inCut = 0;
for(int i = inLeft; i < inRight; i++){
if(inorder[i] == val){
inCut = i;
break;
}
}
//再根据中序数组的左右两部分(个数)切割前序数组为左右两部分
//递归处理他们两个的左右部分
//左闭右开
//中序数组左右部分之间有一个切割点不能取
//但是前序数组左右两部分之间没有切割点,前序数组的切割点在开头,因此第一个不能取
root.left = buildTreePreIn(preorder, preLeft + 1, preLeft + (inCut - inLeft), inorder, inLeft, inCut);
root.right = buildTreePreIn(preorder, preLeft + (inCut - inLeft) + 1, preRight, inorder, inCut + 1, inRight);
//返回结果
return root;
}
}
654 最大二叉树
- 递归:前序遍历(先中间后左右)。
- 输入数组及其起始终止下标位置, 返回二叉树头结点;
- 当输入数组大小小于1时,直接返回,当输入数组大小为1时,该数为叶子节点的值,返回叶子节点;
- 找到数组中最大值和对应的下标,使用最大值构建根节点,使用下标分割数组,再将分割后的左右数组递归继续构建二叉树。分割时注意分割点不加入左右部分,左闭右开。
class Solution {
public TreeNode constructMaximumBinaryTree(int[] nums) {
//开始递归
return buildMaxTree(nums, 0, nums.length);
}
//递归函数
public TreeNode buildMaxTree(int[] nums, int left, int right){
//如果数组为空,直接返回
if(right - left < 1) return null;
//只有一个元素,返回叶子节点
if(right - left == 1) return new TreeNode(nums[left]);
//若数组大于两个元素,则求数组最大值及其下标
int maxVal = nums[left];
int maxIndex = left;
for(int i = left + 1; i < right; i++){
if(nums[i] > maxVal){
maxVal = nums[i];
maxIndex = i;
}
}
//构建根节点
TreeNode root = new TreeNode(maxVal);
//再根据最大值下标切割数组为左右两部分
//递归处理他们两个的左右部分
//左闭右开
//数组左右部分之间有一个切割点不能取
root.left = buildMaxTree(nums, left, left + (maxIndex - left));
root.right = buildMaxTree(nums, left + (maxIndex - left) + 1, right);
//返回结果
return root;
}
}
617 合并二叉树
- 递归:前中后序遍历都可以(建议前序)。
- 输入两棵树的节点,同时操作,返回合并后的根节点;
- 当有一个空节点时返回另一个节点,当全为空节点时返回空;
- 将两棵树的值相加后赋值给节点,可以新建树,也可以直接修改其中一棵树作为结果。
- 迭代:同101 对称二叉树,使用队列模拟层序遍历,将两棵树同一位置节点同时放进队列,一起处理。
- 递归:
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
//前序遍历
//当有一个空节点时返回另一个节点,当全为空节点时返回空
if(root1 == null && root2 == null) return null;
if(root1 == null) return root2;
if(root2 == null) return root1;
//两棵树都不空,将两棵树的值相加后赋值给节点1
//可以新建树,也可以直接修改其中一棵树作为结果
root1.val += root2.val;
//递归处理左右孩子
root1.left = mergeTrees(root1.left, root2.left);
root1.right = mergeTrees(root1.right, root2.right);
//返回结果
return root1;
}
}
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
//当有一个空节点时返回另一个节点,当全为空节点时返回空
if(root1 == null && root2 == null) return null;
if(root1 == null) return root2;
if(root2 == null) return root1;
//前序遍历
//定义队列处理两个元素
Queue<TreeNode> queue = new LinkedList<>();
//初始化队列
queue.offer(root1);
queue.offer(root2);
//开始迭代,当队列为空时结束
while(!queue.isEmpty()){
//将要处理的两个节点出队
TreeNode node1 = queue.poll();
TreeNode node2 = queue.poll();
//此时节点都不为空,将两棵树的值相加后赋值给节点1
//可以新建树,也可以直接修改其中一棵树作为结果
node1.val += node2.val;
//若两个节点的左右孩子都不为空,则入队
if(node1.left != null && node2.left != null){
queue.offer(node1.left);
queue.offer(node2.left);
}
if(node1.right != null && node2.right != null){
queue.offer(node1.right);
queue.offer(node2.right);
}
//若节点1的左右孩子为空且节点2左右孩子不为空,则直接赋值
if(node1.left == null && node2.left != null){
node1.left = node2.left;
}
if(node1.right == null && node2.right != null){
node1.right = node2.right;
}
//若节点1的左右孩子不为空且节点2左右孩子为空,不用处理
}
//返回结果
return root1;
}
}