当前位置: 首页 > news >正文

二叉树进阶:经典算法题详解

二叉树进阶:经典算法题详解

    • 一、双指针相关问题
      • 1.1 判断两棵树是否相同
        • 题目描述
        • 解题思路
        • Java代码实现
      • 1.2 对称二叉树
        • 题目描述
        • 解题思路
        • Java代码实现
      • 1.3 合并二叉树
        • 题目描述
        • 解题思路
        • Java代码实现
    • 二、路径相关问题
      • 2.1 二叉树的所有路径
        • 题目描述
        • 解题思路
        • Java代码实现
      • 2.2 路径总和
        • 题目描述
        • 解题思路
        • Java代码实现
    • 三、经典算法题补充
      • 3.1 翻转二叉树
        • 题目描述
        • 解题思路
        • Java代码实现(递归)
        • Java代码实现(迭代)
      • 3.2 从前序与中序遍历序列构造二叉树
        • 题目描述
        • 解题思路
        • Java代码实现

二叉树作为数据结构中的重要组成部分,其相关算法题在算法竞赛、技术面试以及实际开发中频繁出现,掌握二叉树经典算法题的解题思路与技巧,是进阶算法领域的关键一步。本文我将通过详细解析挑选的几道经典二叉树算法题,结合Java代码实现,帮你深入理解二叉树算法的精髓。

一、双指针相关问题

1.1 判断两棵树是否相同

题目描述

给定两棵二叉树的根节点 pq ,编写一个函数来检验这两棵树是否相同。两棵树被认为是相同的,如果它们的结构相同,并且节点具有相同的值。(LeetCode 100)

解题思路

采用递归的方式同时对两棵树进行前序遍历。从根节点开始,首先判断两棵树的根节点是否都为空,若都为空,则两棵树相同;若其中一个为空,另一个不为空,则两棵树不同。若根节点都不为空且值相等,则继续递归判断左子树和右子树是否相同。

Java代码实现
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}public class SameTree {public boolean isSameTree(TreeNode p, TreeNode q) {// 若两棵树的根节点都为空,返回trueif (p == null && q == null) {return true;}// 若其中一个根节点为空,另一个不为空,返回falseif (p == null || q == null) {return false;}// 若根节点值不相等,返回falseif (p.val != q.val) {return false;}// 递归判断左子树和右子树是否相同return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);}
}

1.2 对称二叉树

题目描述

给定一个二叉树的根节点 root ,检查它是否轴对称。(LeetCode 101)

解题思路

通过递归函数判断二叉树的内侧(左子树的右节点和右子树的左节点)和外侧(左子树的左节点和右子树的右节点)是否对称。首先判断根节点是否为空,若为空则是对称的。然后调用辅助递归函数,判断根节点的左子树和右子树是否对称。在辅助递归函数中,同样先判断两个节点是否都为空,若都为空则对称;若其中一个为空,另一个不为空则不对称;若都不为空且值相等,则继续递归判断内侧和外侧是否对称。

Java代码实现
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}public class SymmetricTree {public boolean isSymmetric(TreeNode root) {if (root == null) {return true;}return isMirror(root.left, root.right);}private boolean isMirror(TreeNode left, TreeNode right) {if (left == null && right == null) {return true;}if (left == null || right == null) {return false;}return (left.val == right.val)&& isMirror(left.left, right.right)&& isMirror(left.right, right.left);}
}

1.3 合并二叉树

题目描述

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。你需要将它们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将它们的值相加作为节点合并后的新值,否则不为 null 的节点将直接作为新二叉树的节点。(LeetCode 617)

解题思路

采用递归的方式合并两棵树。从根节点开始,若其中一棵树为空,则返回另一棵树;若两棵树都不为空,则创建一个新节点,其值为两棵树对应节点值之和,然后递归合并左子树和右子树。

Java代码实现
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}public class MergeTrees {public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {if (t1 == null) {return t2;}if (t2 == null) {return t1;}TreeNode merged = new TreeNode(t1.val + t2.val);merged.left = mergeTrees(t1.left, t2.left);merged.right = mergeTrees(t1.right, t2.right);return merged;}
}

二、路径相关问题

2.1 二叉树的所有路径

题目描述

给定一个二叉树,返回所有从根节点到叶子节点的路径。(LeetCode 257)

解题思路

使用深度优先搜索(DFS)的方法,从根节点开始递归遍历二叉树。在递归过程中,用一个字符串记录从根节点到当前节点的路径。当到达叶子节点时,将该路径加入结果列表中。对于每个节点,递归处理其左子树和右子树,并在递归返回时回溯,恢复路径字符串的状态。

Java代码实现
import java.util.ArrayList;
import java.util.List;class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}public class BinaryTreePaths {public List<String> binaryTreePaths(TreeNode root) {List<String> paths = new ArrayList<>();if (root == null) {return paths;}dfs(root, "", paths);return paths;}private void dfs(TreeNode node, String path, List<String> paths) {path += node.val;if (node.left == null && node.right == null) {paths.add(path);return;}if (node.left != null) {dfs(node.left, path + "->", paths);}if (node.right != null) {dfs(node.right, path + "->", paths);}}
}

2.2 路径总和

题目描述

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 从根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。叶子节点 是指没有子节点的节点。(LeetCode 112)

解题思路

将问题拆解为子问题,使用递归的方式从根节点开始判断。首先判断根节点是否为空,若为空则直接返回 false 。然后判断根节点是否为叶子节点且其值等于目标和,若是则返回 true 。否则,递归判断左子树和右子树是否存在满足条件的路径,即将目标和减去当前节点的值后,继续在子树中寻找。

Java代码实现
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}public class PathSum {public boolean hasPathSum(TreeNode root, int targetSum) {if (root == null) {return false;}if (root.left == null && root.right == null && root.val == targetSum) {return true;}return hasPathSum(root.left, targetSum - root.val) || hasPathSum(root.right, targetSum - root.val);}
}

三、经典算法题补充

3.1 翻转二叉树

题目描述

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。(LeetCode 226)

解题思路

可以使用递归或迭代的方式实现。递归方式下,从根节点开始,交换其左右子树,然后递归地翻转左子树和右子树。迭代方式可以使用栈来模拟递归过程,先将根节点入栈,然后在栈不为空时,弹出节点,交换其左右子树,并将非空的左右子节点入栈,直到栈为空。

Java代码实现(递归)
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}public class InvertBinaryTree {public TreeNode invertTree(TreeNode root) {if (root == null) {return null;}TreeNode left = invertTree(root.left);TreeNode right = invertTree(root.right);root.left = right;root.right = left;return root;}
}
Java代码实现(迭代)
import java.util.Stack;class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}public class InvertBinaryTreeIterative {public TreeNode invertTree(TreeNode root) {if (root == null) {return null;}Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.pop();TreeNode temp = node.left;node.left = node.right;node.right = temp;if (node.left != null) {stack.push(node.left);}if (node.right != null) {stack.push(node.right);}}return root;}
}

3.2 从前序与中序遍历序列构造二叉树

题目描述

给定两个整数数组 preorderinorder ,其中 preorder 是二叉树的前序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。(LeetCode 105)

解题思路

前序遍历的第一个元素是根节点的值,在中序遍历中找到该值的位置,这个位置将中序遍历序列分为左子树和右子树两部分。根据左子树和右子树的节点数量,可以在前序遍历序列中划分出左子树和右子树的前序遍历部分。然后递归地构造左子树和右子树,最终得到整棵二叉树。

Java代码实现
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}public class BuildTree {public TreeNode buildTree(int[] preorder, int[] inorder) {return buildTree(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);}private TreeNode buildTree(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd) {if (preStart > preEnd || inStart > inEnd) {return null;}int rootVal = preorder[preStart];TreeNode root = new TreeNode(rootVal);int inIndex = 0;for (int i = inStart; i <= inEnd; i++) {if (inorder[i] == rootVal) {inIndex = i;break;}}int leftSize = inIndex - inStart;root.left = buildTree(preorder, preStart + 1, preStart + leftSize, inorder, inStart, inIndex - 1);root.right = buildTree(preorder, preStart + leftSize + 1, preEnd, inorder, inIndex + 1, inEnd);return root;}
}

That’s all, thanks for reading!
觉得有用就点个赞、收进收藏夹吧!关注我,获取更多干货~

http://www.xdnf.cn/news/971551.html

相关文章:

  • AD8539ARZ ADI 精密放大器 电子元器件解析
  • 判断素数两种方法【自用】
  • 【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
  • 工作中开发的sql总结
  • LeetCode 200.岛屿数量
  • 天猫官方认证TP服务商——品融电商代运营全链路解析
  • 无需安装!在线 SQL 数据库工具实战 :经典 SQL 语句案例
  • NY167NY171美光固态闪存NY176NY180
  • 《炒股进阶:MACD交易技术从入门到精通》速读笔记
  • Nature子刊|ChatNT:生物多模态LLM破壁者!统一DNA/RNA/蛋白质分析的对话式AI
  • JAVA中的多线程
  • 常见算法题目6 - 给定一个字符串,输出其最长的回文子串
  • F5 BIG IP show running config
  • 模型参数、模型存储精度、参数与显存
  • Postman参数化详解
  • leetcode_35.搜索插入位置
  • 如何查看电脑系统的初始安装时间?
  • 龙虎榜——20250610
  • 【沉浸式求职学习day53】【Spring】
  • MFC 第一章概述
  • 2025 Java 面试大全
  • 39.第二阶段x64游戏实战-封包-分析计数器
  • gro文件和top文件介绍,以及如何合并两个gro文件或两个top文件
  • 【论文解读】ReSearch:让LLM自主学习搜索
  • Qt进阶开发:动画框架的介绍和使用
  • Zynq multi boot及网口远程更新开发
  • Android Studio 问题:Android Studio 一直开在 Updating indexes
  • 【运维】【期末实训】网站简易搭建模拟
  • 核心机制:面向字节流
  • C++:std::is_convertible