跳到主要内容Java 二叉树修改与构造经典题目解析 | 极客日志Javajava算法
Java 二叉树修改与构造经典题目解析
本文整理了四道经典的二叉树操作 LeetCode 题目,涵盖翻转二叉树、从中序与后序遍历序列构造二叉树、构造最大二叉树以及合并两个二叉树。针对每道题提供了详细的解题思路、递归终止条件及单层逻辑分析,并附上了完整的 Java 实现代码。内容旨在帮助开发者理解二叉树的分治与递归思想,适用于算法学习与面试复习。
本文系统梳理了二叉树修改与改造在 LeetCode 上的热门题目,包含完整 Java 代码及关键逻辑解析。
1. 226. 翻转二叉树
题目链接: 226. 翻转二叉树 - LeetCode
思路
- 构造一个交换函数用于交换子树的左右节点
- 遍历左子树
- 遍历右子树
实现步骤
- 确定递归返回值和参数:参数为传入节点的指针,无需其他参数。
public TreeNode invertTree(TreeNode root) {
}
- 终止条件:当前节点为空即返回。
if (root == null) return null;
- 单层递归逻辑:遍历左子树,遍历右子树,对子树的左右节点进行交换。
invertTree(root.left);
invertTree(root.right);
swapChildren(root);
return root;
private void swapChildren(TreeNode root) {
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
}
- 最终代码
class Solution_226 {
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
invertTree(root.left);
invertTree(root.right);
swapChildren(root);
return root;
}
private void swapChildren {
root.left;
root.left = root.right;
root.right = tmp;
}
}
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
(TreeNode root)
TreeNode
tmp
=
2. 106. 从中序与后序遍历序列构造二叉树
思路
- 由中序与后序构成二叉树,后序的最后一个为中序的根节点
- 以根节点为分割线,分割为两个子数组,一值递归
实现步骤
- 确定递归返回值和参数:需要传递两个数组的有效区间(避免频繁拷贝子数组),使用左闭右开区间是为了统一边界处理。
private TreeNode buildHelper(int[] inorder, int inorderStart, int inorderEnd,
int[] postorder, int postorderStart, int postorderEnd) {
}
- 终止条件:当前子树为空 → 区间无效。在左闭右开约定下:
postorderStart == postorderEnd 表示无节点。
if (postorderStart == postorderEnd) return null;
-
单层递归逻辑
- Step 1: 从后序数组取根节点
后序遍历:
[左子树 | 右子树 | 根],所以最后一个元素是根。
int rootVal = postorder[postorderEnd - 1];
TreeNode root = new TreeNode(rootVal);
- Step 2: 在中序数组中找根的位置
中序遍历:
[左子树 | 根 | 右子树],找到 rootVal 的索引 middleIndex,即可划分左右子树。
int middleIndex;
for (middleIndex = inorderStart; middleIndex < inorderEnd; middleIndex++) {
if (inorder[middleIndex] == rootVal) break;
}
- Step 3: 计算左右子树在中序中的区间
左子树中序:
[inorderStart, middleIndex)
右子树中序:[middleIndex + 1, inorderEnd)
int leftInorderStart = inorderStart;
int leftInorderEnd = middleIndex;
int rightInorderStart = middleIndex + 1;
int rightInorderEnd = inorderEnd;
- Step 4: 计算左右子树在后序中的区间(关键!)
左子树节点数 =
middleIndex - inorderStart
后序中:左子树后序从 postorderStart 开始,长度一致;右子树后序紧跟左子树之后,到 postorderEnd - 1(排除根)。
int leftPostorderStart = postorderStart;
int leftPostorderEnd = postorderStart + (middleIndex - inorderStart);
int rightPostorderStart = leftPostorderEnd;
int rightPostorderEnd = postorderEnd - 1;
root.left = buildHelper(inorder, leftInorderStart, leftInorderEnd,
postorder, leftPostorderStart, leftPostorderEnd);
root.right = buildHelper(inorder, rightInorderStart, rightInorderEnd,
postorder, rightPostorderStart, rightPostorderEnd);
class Solution_106 {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if (inorder.length == 0 || postorder.length == 0) {
return null;
}
return buildHelper(inorder, 0, inorder.length, postorder, 0, postorder.length);
}
private TreeNode buildHelper(int[] inorder, int inorderStart, int inorderEnd,
int[] postorder, int postorderStart, int postorderEnd) {
if (postorderStart == postorderEnd) return null;
int rootVal = postorder[postorderEnd - 1];
TreeNode root = new TreeNode(rootVal);
int middleIndex;
for (middleIndex = inorderStart; middleIndex < inorderEnd; middleIndex++) {
if (inorder[middleIndex] == rootVal) break;
}
int leftInorderStart = inorderStart;
int leftInorderEnd = middleIndex;
int rightInorderStart = middleIndex + 1;
int rightInorderEnd = inorderEnd;
int leftPostorderStart = postorderStart;
int leftPostorderEnd = postorderStart + (middleIndex - inorderStart);
int rightPostorderStart = leftPostorderEnd;
int rightPostorderEnd = postorderEnd - 1;
root.left = buildHelper(inorder, leftInorderStart, leftInorderEnd,
postorder, leftPostorderStart, leftPostorderEnd);
root.right = buildHelper(inorder, rightInorderStart, rightInorderEnd,
postorder, rightPostorderStart, rightPostorderEnd);
return root;
}
}
3. 654. 构造最大二叉树
思路
- 分解:在当前数组中找到最大值,作为根
- 治理:最大值左侧 → 左子树;右侧 → 右子树
- 合并:将左右子树挂到根上,返回根节点
实现步骤
- 确定递归返回值和参数:
- 返回值:当前子数组对应的最大二叉树的根节点 →
TreeNode
- 参数:
int[] nums、int leftIndex、int rightIndex
public TreeNode constructMaximumBinaryTree(int[] nums, int leftIndex, int rightIndex) {
}
- 终止条件:
- 当前子数组为空:
rightIndex - leftIndex < 1 → 返回 null
- 当前子数组只有一个元素:直接返回该值的节点
if (rightIndex - leftIndex < 1) {
return null;
}
if (rightIndex - leftIndex == 1) {
return new TreeNode(nums[leftIndex]);
}
-
单层递归逻辑
- Step 1: 在当前区间
[leftIndex, rightIndex) 中找到最大值及其下标
int maxIndex = leftIndex;
int maxValue = nums[maxIndex];
for (int i = leftIndex + 1; i < rightIndex; i++) {
if (nums[i] > maxValue) {
maxValue = nums[i];
maxIndex = i;
}
}
TreeNode root = new TreeNode(maxValue);
- Step 3: 递归构建左右子树
左区间:
[leftIndex, maxIndex);右区间:[maxIndex + 1, rightIndex)
root.left = constructMaximumBinaryTree(nums, leftIndex, maxIndex);
root.right = constructMaximumBinaryTree(nums, maxIndex + 1, rightIndex);
return root;
class Solution_654 {
public TreeNode constructMaximumBinaryTree(int[] nums) {
return constructMaximumBinaryTree(nums, 0, nums.length);
}
public TreeNode constructMaximumBinaryTree(int[] nums, int leftIndex, int rightIndex) {
if (rightIndex - leftIndex < 1) {
return null;
}
if (rightIndex - leftIndex == 1) {
return new TreeNode(nums[leftIndex]);
}
int maxIndex = leftIndex;
int maxValue = nums[maxIndex];
for (int i = leftIndex + 1; i < rightIndex; i++) {
if (nums[i] > maxValue) {
maxValue = nums[i];
maxIndex = i;
}
}
TreeNode root = new TreeNode(maxValue);
root.left = constructMaximumBinaryTree(nums, leftIndex, maxIndex);
root.right = constructMaximumBinaryTree(nums, maxIndex + 1, rightIndex);
return root;
}
}
4. 617. 合并两个二叉树
思路
实现步骤
- 确定递归返回值和参数:
- 参数:当前要合并的两个节点
root1 和 root2
- 返回值:合并后子树的根节点(
TreeNode)
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
}
- 终止条件:
- 如果
root1 == null,说明当前位置只有 root2 有节点 → 直接返回 root2
- 如果
root2 == null,说明当前位置只有 root1 有节点 → 直接返回 root1
if (root1 == null) return root2;
if (root2 == null) return root1;
-
单层递归逻辑
- Step 1: 合并当前节点的值
- Step 2: 递归合并左右子树
root1.val += root2.val;
root1.left = mergeTrees(root1.left, root2.left);
root1.right = mergeTrees(root1.right, root2.right);
return root1;
class Solution_617 {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if (root1 == null) return root2;
if (root2 == null) return root1;
root1.val += root2.val;
root1.left = mergeTrees(root1.left, root2.left);
root1.right = mergeTrees(root1.right, root2.right);
return root1;
}
}