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

leetcode257二叉树的所有路径

找出所有根节点到叶子结点的路径,这题比较容易想到的是回溯,不过层序遍历用两个队列也可以实现。这里还是只讲回溯

回溯版本一:

递归函数作用:处理传入结点的所有子孙结点,形成以其左右孩子为起点的到各叶子结点的路径。遍历到叶子结点时,组装当前这条路径结果

回溯状态:path集合

递归出口:遍历到叶子结点时,组装当前这条路径结果

第一步:根结点加入path

第二步:将根结点的左孩子结点加入path, 递归处理根结点的左孩子结点,处理完后,移除path中保存的根结点的左孩子结点,此时path中只有根结点

第三步:将根结点的右孩子结点加入path, 递归处理根结点的右孩子结点,处理完后,移除path中保存的根结点的右孩子结点,此时path中只有根结点

class Solution { public List<String> binaryTreePaths(TreeNode root) { List<String> res = new ArrayList<>(); //根结点为空,直接返回空集合 if (root == null) return res; //path用来装某条路径上的所有结点 List<Integer> path = new ArrayList<>(); //根结点的值先加入path path.add(root.val); //处理根结点的所有子孙结点,加到相应的路径结果中 dfs(root, path, res); // System.out.println(path); return res; } /** *递归函数作用:处理传入结点的所有子孙结点,形成以其左右孩子为起点的各种到叶子结点的路径。 *遍历到叶子结点时,组装当前这条路径结果 */ private void dfs(TreeNode node, List<Integer> path, List<String> res) { // 如果是叶子结点:把整条路径拼接成字符串 if (node.left == null && node.right == null) { res.add(joinPath(path)); return; } //如果存在左孩子结点 if (node.left != null) { //左孩子结点值加入path path.add(node.left.val); //递归处理左孩子的所有子孙结点 dfs(node.left, path, res); //将path中的左孩子结点值移除 path.remove(path.size() - 1); } //如果存在右孩子结点 if (node.right != null) { //右孩子结点值加入path path.add(node.right.val); //递归处理右孩子的所有子孙结点 dfs(node.right, path, res); //将path中的右孩子结点值移除 path.remove(path.size() - 1); } } //将path中的结点值拼接成想要的字符串 private String joinPath(List<Integer> path) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < path.size(); i++) { if (i > 0) sb.append("->"); sb.append(path.get(i)); } return sb.toString(); } }

remove结点版:

class Solution { public List<String> binaryTreePaths(TreeNode root) { List<String> res = new ArrayList<>(); if (root == null) return res; List<TreeNode> path = new ArrayList<>(); path.add(root); dfs(root, path, res); return res; } private void dfs(TreeNode node, List<TreeNode> path, List<String> res) { //如果是叶子结点:把整条路径拼接成字符串 if (node.left == null && node.right == null) { res.add(joinPath(path)); } else { if (node.left != null) { path.add(node.left); dfs(node.left, path, res); path.remove(node.left); } if (node.right != null) { path.add(node.right); dfs(node.right, path, res); path.remove(node.right); } } } private String joinPath(List<TreeNode> path) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < path.size(); i++) { if (i > 0) sb.append("->"); sb.append(Integer.toString(path.get(i).val)); } return sb.toString(); } }

回溯版本二:

递归函数作用:处理传入结点为根的二叉树所有结点,形成传入结点到各叶子结点的路径。遍历到叶子结点时,组装当前这条路径结果

回溯状态:path集合

递归出口:遍历到叶子结点时,组装当前这条路径结果

第一步:将根结点值加入path

第二步:递归处理根结点的左子树

第三步:递归处理根节点的右子树

最后:移除path中根节点值,此时,path为空

为什么最后要移除path中根节点值?

以上图中的左子树为例

左子树根结点的左右孩子处理完成的时候,path中有整颗二叉树的根结点值和其左子树的根结点值,接下来该处理整棵二叉树的右子树了,因此path中左子树的根结点值需要移除掉。

import java.util.*; class Solution { public List<String> binaryTreePaths(TreeNode root) { List<String> res = new ArrayList<>(); if (root == null) return res; List<Integer> path = new ArrayList<>(); dfs(root, path, res); return res; } private void dfs(TreeNode node, List<Integer> path, List<String> res) { // 1) 记录当前结点到路径 path.add(node.val); // 2) 如果是叶子结点:把整条路径拼接成字符串 if (node.left == null && node.right == null) { res.add(joinPath(path)); } else { if (node.left != null) dfs(node.left, path, res); if (node.right != null) dfs(node.right, path, res); } // 3) 回溯:撤销当前结点 path.remove(path.size() - 1); } private String joinPath(List<Integer> path) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < path.size(); i++) { if (i > 0) sb.append("->"); sb.append(path.get(i)); } return sb.toString(); } }

remove结点版:

class Solution { public List<String> binaryTreePaths(TreeNode root) { List<String> res = new ArrayList<>(); if (root == null) return res; List<TreeNode> path = new ArrayList<>(); dfs(root, path, res); return res; } private void dfs(TreeNode node, List<TreeNode> path, List<String> res) { path.add(node); //如果是叶子结点:把整条路径拼接成字符串 if (node.left == null && node.right == null) { res.add(joinPath(path)); } else { if (node.left != null) { dfs(node.left, path, res); } if (node.right != null) { dfs(node.right, path, res); } } path.remove(node); } private String joinPath(List<TreeNode> path) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < path.size(); i++) { if (i > 0) sb.append("->"); sb.append(Integer.toString(path.get(i).val)); } return sb.toString(); } }

回溯版本三:

这种方式虽然也是对的,但是不标准,推荐版本一和版本二,那种当前层代码移除当前层状态的方式!!!

import java.util.*; class Solution { public List<String> binaryTreePaths(TreeNode root) { List<String> res = new ArrayList<>(); if (root == null) return res; List<Integer> path = new ArrayList<>(); dfs(root, path, res); return res; } private void dfs(TreeNode node, List<Integer> path, List<String> res) { // 1) 记录当前结点到路径 path.add(node.val); // 2) 如果是叶子结点:把整条路径拼接成字符串 if (node.left == null && node.right == null) { res.add(joinPath(path)); } else { if (node.left != null) { dfs(node.left, path, res); //移除的是上面代码调用加入的node.left //属于父结点层移除左孩子 path.remove(path.size() - 1); } if (node.right != null){ dfs(node.right, path, res); //移除的是上面代码调用加入的node.right //属于父结点层移除右孩子 path.remove(path.size() - 1); } } } private String joinPath(List<Integer> path) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < path.size(); i++) { if (i > 0) sb.append("->"); sb.append(path.get(i)); } return sb.toString(); } }

remove结点版:

class Solution { public List<String> binaryTreePaths(TreeNode root) { List<String> res = new ArrayList<>(); if (root == null) return res; List<TreeNode> path = new ArrayList<>(); dfs(root, path, res); return res; } private void dfs(TreeNode node, List<TreeNode> path, List<String> res) { path.add(node); //如果是叶子结点:把整条路径拼接成字符串 if (node.left == null && node.right == null) { res.add(joinPath(path)); } else { if (node.left != null) { dfs(node.left, path, res); path.remove(node.left); } if (node.right != null) { dfs(node.right, path, res); path.remove(node.right); } } } private String joinPath(List<TreeNode> path) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < path.size(); i++) { if (i > 0) sb.append("->"); sb.append(Integer.toString(path.get(i).val)); } return sb.toString(); } }
http://www.jsqmd.com/news/157724/

相关文章:

  • 阴阳师自动挂机:智能解放双手的高效刷魂方案
  • Step-Audio-Tokenizer:1300亿参数语音语义编码新突破
  • MinIO Console:让对象存储管理像使用文件管理器一样简单
  • 拯救你的B站收藏!m4s-converter一键转换缓存视频永久保存指南
  • Zotero PDF Translate插件终极指南:如何快速提升科研翻译效率
  • 实战:RK3568 Android14 集成 AP6212A WiFi/BT 二合一模块
  • LaserGRBL深度实战:从入门到精通的激光雕刻控制指南
  • 番茄小说下载器:3种方法解决你的离线阅读痛点
  • Chinese医疗对话数据集完整指南:构建智能问诊系统的高效方法
  • Qwen3-32B-GGUF:本地AI双模式推理终极指南
  • 2025年四川成都菜籽油批发服务商综合评估与优选指南 - 2025年品牌推荐榜
  • DeTikZify终极指南:零基础快速掌握AI绘图神器
  • Zotero PDF Translate插件翻译窗口笔记功能深度解析:为什么“添加到笔记“按钮有时不显示?
  • PyTorch-CUDA-v2.6镜像支持FlashAttention-2进一步提速
  • 如何10分钟掌握dynamic-datasource:SpringBoot多数据源动态切换实战手册
  • 如何用3分钟掌握JSONDiff:数据对比的终极解决方案
  • 为什么在CSDN发布的评论会被折叠?
  • BetterNCM-Installer终极指南:3步轻松管理网易云音乐插件
  • Zotero PDF Translate终极指南:修复翻译窗口笔记功能不显示问题
  • 3步打造完美音乐库:Music Tag Web智能标签管理终极指南
  • MZmine 3质谱数据分析实战:从零基础到专业级应用
  • 5分钟彻底解决Windows热键冲突:快捷键侦探实战手册
  • D3KeyHelper深度测评报告:暗黑3游戏自动化操作实战指南
  • iperf3网络性能测试权威指南:精准评估带宽瓶颈的实战手册
  • 通俗解释rs485modbus协议源代码底层驱动分层结构
  • 2025年知名的泡沫蹲便器/防臭蹲便器实力厂家TOP推荐榜 - 行业平台推荐
  • B站m4s转mp4终极指南:3步搞定视频永久保存
  • MinIO Console图形化管理工具的终极指南:从入门到精通
  • 解决 macOS 使用 screen 命令闪退:与 Linux 环境对比
  • OpenWrt网易云音乐解锁完全攻略:5步实现全网音乐畅听