leetcode 257. 二叉树的所有路径 包含(二叉树的先序遍历、中序遍历、后序遍历)
给定一个二叉树,返回所有从根节点到叶子节点的路径。
说明: 叶子节点是指没有子节点的节点。
示例:
输入:
1
/ \
2 3
\
5
输出: ["1->2->5", "1->3"]
解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
首先来看递归版本:
static void dfs(TreeNode root, String path, LinkedList<String> paths){
if(root.left == null && root.right ==null){
paths.add(path + root.val);
return;
}
if(root.left != null) {
dfs(root.left, path + root.val + "->", paths);
}
if(root.right != null ) {
dfs(root.right, path + root.val + "->", paths);
}
}
public static List<String> binaryTreePaths(TreeNode root) {
LinkedList<String> paths = new LinkedList();
//递归版本
// dfs(root, "", paths);
return paths;
}
那么如何将其改为非递归版本呢,我们利用后序遍历模板与先序遍历模板来实现。
解法一
static void iteration(TreeNode root, LinkedList<String> paths) {
Stack<TreeNode> s = new Stack<>();
TreeNode p = root;
TreeNode pre = null;
while(p != null ){
s.push(p);
p = p.left ;
}
while(!s.empty()){
p = s.peek();
if(p.right!=null && p.right != pre){
p = p.right;
while(p != null ){
s.push(p);
p = p.left ;
}
pre =null;
}
else{
if(pre == null ) {
paths.add(getPath(s, "->"));
}
pre = s.pop();
}
}
System.out.println();
}
public static List<String> binaryTreePaths(TreeNode root) {
LinkedList<String> paths = new LinkedList();
//递归版本
// dfs(root, "", paths);
//非递归版本
iteration(root, paths);
return paths;
}
private static String getPath(Stack<TreeNode> s, String sp) {
// Iterator<TreeNode> it = s.iterator();
StringBuilder buf = new StringBuilder();
// while (it.hasNext()) {
// if (buf.length() != 0) {
// buf.append(sp);
// }
// buf.append(String.valueOf(it.next().value));
// }
for(TreeNode node : s){
if (buf.length() != 0) {
buf.append(sp);
}
buf.append(String.valueOf(node.val));
}
return buf.toString();
}
解法二
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
LinkedList<String> paths = new LinkedList();
if (root == null)
return paths;
LinkedList<TreeNode> node_stack = new LinkedList();
LinkedList<String> path_stack = new LinkedList();
node_stack.add(root);
path_stack.add(Integer.toString(root.val));
TreeNode node;
String path;
while (!node_stack.isEmpty()) {
node = node_stack.pollLast();
path = path_stack.pollLast();
if ((node.left == null) && (node.right == null))
paths.add(path);
if (node.left != null) {
node_stack.add(node.left);
path_stack.add(path + "->" + Integer.toString(node.left.val));
}
if (node.right != null) {
node_stack.add(node.right);
path_stack.add(path + "->" + Integer.toString(node.right.val));
}
}
return paths;
}
}
在这里我们用两种模板完整地实现二叉树的先序遍历,中序遍历,后序遍历。
思想一: 在从栈里弹出节点的时候,此时压入左右节点
public static void PreOrderTraversal(TreeNode root){
Stack<TreeNode> s = new Stack<>();
TreeNode p = root;
s.push(p);
while(!s.empty()){
TreeNode node = s.pop();
if(node == null ){
continue;
}
System.out.print(node.val+" ");
if(node.right != null ) {
s.push(node.right);
}
if(node.left != null ){
s.push(node.left);
}
}
System.out.println();
}
public static void PostOrderTraversal(TreeNode root){
List<Integer> res = new ArrayList<>();
Stack<TreeNode> s = new Stack<>();
TreeNode p = root;
s.push(p);
while(!s.empty()){
TreeNode node = s.pop();
if(node == null ){
continue;
}
// System.out.print(node.val+" ");
res.add(node.val);
if(node.left != null ) {
s.push(node.left);
}
if(node.right != null ){
s.push(node.right);
}
}
Collections.reverse(res);
System.out.println(res);
}
思想二: 从栈中弹出节点的时候,一直压入左孩子,直到为空,对于栈顶节点来说,如果有右孩子,压入右孩子,否则一直弹。
后序遍历比较特殊,对于某一节点来说,需要判断是从左右节点哪个节点访问。
public static void PreOrderWithoutRecursion(TreeNode root){
Stack<TreeNode> s = new Stack<>();
TreeNode p = root;
while(p != null || !s.empty()){
if(p != null ){
System.out.print(p.val +" ");
s.push(p);
p = p.left ;
}
else{
p = s.pop();
p = p .right;
}
}
System.out.println();
}
public static void InOrderWithoutRecursion(TreeNode root){
Stack<TreeNode> s = new Stack<>();
TreeNode p = root;
while(p != null || !s.empty()){
if(p != null ){
s.push(p);
p = p.left ;
}
else{
p = s.pop();
System.out.print(p.val +" ");
p = p.right;
}
}
System.out.println();
}
public static void PostOrderWithoutRecursion(TreeNode root){
Stack<TreeNode> s = new Stack<>();
TreeNode p = root;
TreeNode pLastVistNode = null;
while(p != null ){
s.push(p);
p = p.left ;
}
while(!s.empty()){
p = s.pop();
if( p.right == null || p.right == pLastVistNode){
System.out.print(p.val+" ");
pLastVistNode = p;
}
else{
s.push(p);
p = p.right;
while(p != null){
s.push(p);
p = p.left;
}
}
}
System.out.println();
}
leetcode 257. 二叉树的所有路径 包含(二叉树的先序遍历、中序遍历、后序遍历)的更多相关文章
- LeetCode 145. 二叉树的后序遍历 (用栈实现后序遍历二叉树的非递归算法)
题目链接:https://leetcode-cn.com/problems/binary-tree-postorder-traversal/ 给定一个二叉树,返回它的 后序 遍历. 示例: 输入: [ ...
- PAT树_层序遍历叶节点、中序建树后序输出、AVL树的根、二叉树路径存在性判定、奇妙的完全二叉搜索树、最小堆路径、文件路由
03-树1. List Leaves (25) Given a tree, you are supposed to list all the leaves in the order of top do ...
- [leetcode]从中序与后序/前序遍历序列构造二叉树
从中序与后序遍历序列构造二叉树 根据一棵树的中序遍历与后序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 中序遍历 inorder = [9,3,15,20,7] 后序遍历 po ...
- Leetcode(106)-从中序与后序遍历序列构造二叉树
根据一棵树的中序遍历与后序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 中序遍历 inorder = [9,3,15,20,7] 后序遍历 postorder = [9,15,7 ...
- (原)neuq oj 1022给定二叉树的前序遍历和后序遍历确定二叉树的个数
题目描述 众所周知,遍历一棵二叉树就是按某条搜索路径巡访其中每个结点,使得每个结点均被访问一次,而且仅被访问一次.最常使用的有三种遍历的方式: 1.前序遍历:若二叉树为空,则空操作:否则先访问根结点, ...
- 小小c#算法题 - 11 - 二叉树的构造及先序遍历、中序遍历、后序遍历
在上一篇文章 小小c#算法题 - 10 - 求树的深度中,用到了树的数据结构,树型结构是一类重要的非线性数据结构,树是以分支关系定义的层次结构,是n(n>=0)个结点的有限集.但在那篇文章中,只 ...
- 二叉排序树的构造 && 二叉树的先序、中序、后序遍历 && 树的括号表示规则
二叉排序树的中序遍历就是按照关键字的从小到大顺序输出(先序和后序可没有这个顺序) 一.以序列 6 8 5 7 9 3构建二叉排序树: 二叉排序树就是中序遍历之后是有序的: 构造二叉排序树步骤如下: 插 ...
- 二叉树后序遍历的非递归算法(C语言)
首先非常感谢‘hicjiajia’的博文:二叉树后序遍历(非递归) 这篇随笔开启我的博客进程,成为万千程序员中的一员,坚持走到更远! 折磨了我一下午的后序遍历中午得到解决,关键在于标记右子树是否被访问 ...
- LintCode2016年8月8日算法比赛----中序遍历和后序遍历构造二叉树
中序遍历和后序遍历构造二叉树 题目描述 根据中序遍历和后序遍历构造二叉树 注意事项 你可以假设树中不存在相同数值的节点 样例 给出树的中序遍历: [1,2,3] 和后序遍历: [1,3,2] 返回如下 ...
随机推荐
- ReaderWriterLockSlim使用示例
/// <summary> /// ReaderWriterLockSlim使用示例 /// </summary> internal sealed class Transact ...
- 团队第三次作业:Alpha版本第一周小结
姓名 学号 周前计划安排 每周实际工作记录 自我打分 XXX 061109 1.原型设计与编码任务分配 2.构思程序个性化测试模块的初步实现 1.原型设计与编码任务分配 2.设计了部分类及其成员函数( ...
- Java Listener
六. Java Listener 1. Java Listener 简介 * Java Listener 1. Java Listener(即:Java 监听器):用于监听 ServletRequ ...
- okhttp任务调度核心类dispatcher解析
在之前已经对okhttp的同步和异步请求的流程进行了详细的分析,其中任务调度是由dispatcher来实现的,非常重要,所以这次专门来对它进行一个了解,带着问题去进行探究: Q1:okhttp如何实现 ...
- BZOJ1791 [Ioi2008]Island 岛屿[基环树+单调队列优化DP]
基环树直径裸题. 首先基环树直径只可能有两种形式:每棵基环树中的环上挂着的树的直径,或者是挂在环上的两个树的最大深度根之间的距离之和. 所以,先对每个连通块跑一遍,把环上的点找出来,然后对环上每个点跑 ...
- Python JSON Ⅱ
json.loads json.loads 用于解码 JSON 数据.该函数返回 Python 字段的数据类型. 语法 实例 以下实例展示了Python 如何解码 JSON 对象: 以上代码执行结果为 ...
- 编码问题2 utf-8和Unicode的区别
utf-8和Unicode到底有什么区别?是存储方式不同?编码方式不同?它们看起来似乎很相似,但是实际上他们并不是同一个层次的概念 要想先讲清楚他们的区别,首先应该讲讲Unicode的来由. 众所周知 ...
- hover([over,]out)
hover([over,]out) 概述 一个模仿悬停事件(鼠标移动到一个对象上面及移出这个对象)的方法.这是一个自定义的方法,它为频繁使用的任务提供了一种“保持在其中”的状态. 当鼠标移动到一个匹配 ...
- Java 面试题 二
1.线程怎么保持同步 关于线程同步(7种方式) --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3897440.html"谢谢 ...
- 微信支付宝xposed个人收款免签支付源码
源码介绍: 个人免签支付是指使用自己的微信支付宝账号作为个人网站的收款账号,网站订单支付成功后,网站能实时收到成功回调信息. 系统基于xposed逆向微信.支付宝.云闪付来实现个人收款免 ...