当前位置: 首页 > 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!
觉得有用就点个赞、收进收藏夹吧!关注我,获取更多干货~

相关文章:

  • 6月10日day50打卡
  • 可视化图解算法50:最小的K个数
  • SpringBoot集成Tess4j :低成本解锁OCR 图片识别能力
  • 鹰盾视频的AI行为检测是怎样的风控?
  • [极客时间]LangChain 实战课 ----- 01|LangChain系统安装和快速入门(2)
  • 第四章 软件需求工程
  • 论文略读: CUT YOUR LOSSES IN LARGE-VOCABULARY LANGUAGE MODELS
  • 如何通过DNS解析实现负载均衡?有哪些优势?
  • 期权卖方是谁?
  • Linux动态库与静态库详解:从入门到精通
  • mysql-innoDB存储引擎事务的原理
  • 智能合约安全专题(一):什么是重入攻击?——从 DAO 事件谈起
  • Ribbon负载均衡实战指南:7种策略选择与生产避坑
  • 《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
  • 广告系统中后链路数据为什么要使用流批一体技术?流批一体技术是什么?
  • [特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
  • Redis高可用与扩展性:构建稳定高效的缓存系统
  • Qt Widget类解析与代码注释
  • 图像直方图分析:全面掌握OpenCV与Matplotlib绘制技巧
  • python整数处理 2022年信息素养大赛复赛/决赛真题 小学组/初中组 python编程挑战赛 真题详细解析
  • 顺德网站建设找顺的/影响关键词优化的因素
  • asp.net 4.0网站建设基础教程/一手项目对接app平台
  • 如何做网站充值/重庆百度seo整站优化
  • 可以做微信游戏的网站有哪些/厦门seo网站推广优化
  • 开封建站公司/河南网站seo费用
  • 销售网站建设公司/上海疫情最新情况