题目:

Given a binary tree, return the postorder traversal of its nodes' values.

For example:
Given binary tree {1,#,2,3},

   1
\
2
/
3

return [3,2,1].

Note: Recursive solution is trivial, could you do it iteratively?

链接: http://leetcode.com/problems/binary-tree-postorder-traversal/

题解:

二叉树后序遍历。 刚接触leetcode时也做过这道题,用了很蠢笨的方法。现在学习discuss里大神们的版本,真的进步很多。下面这个版本是基于上道题目 - 二叉树先序遍历的。由于后序遍历是left -> right -> root,  先序是root -> left -> right, 所以我们改变的只是如何插入结果到 list里,以及被压入栈的先后顺序而已。在这里,pop出的结果要插入到list前部,而且要先把左子树压入栈,其次是右子树。

Time Complexity - O(n),Space Complexity - O(n)。

/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new LinkedList<>();
if(root == null)
return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root); while(!stack.isEmpty()) {
TreeNode node = stack.pop();
if(node != null) {
res.add(0, node.val); // insert at the front of list
stack.push(node.left); // opposite push
stack.push(node.right);
}
} return res;
}
}

二刷:

Java:

/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new LinkedList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root); while (!stack.isEmpty()) {
TreeNode node = stack.pop();
if (node != null) {
res.add(0, node.val);
stack.push(node.left);
stack.push(node.right);
}
}
return res;
}
}

Recursive:

/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
postorderTraversal(res, root);
return res;
} private void postorderTraversal(List<Integer> res, TreeNode root) {
if (root == null) return;
postorderTraversal(res, root.left);
postorderTraversal(res, root.right);
res.add(root.val);
}
}

三刷:

Java:

Reversed preorder traversal with LinkedList and Stack:

主要使用一个LinkedList和一个stack来辅助我们的遍历。其实顺序和pre-order并没有区别,只是把遍历过的节点值不断从链表头部插入,也就形成了我们的后续遍历。注意处理节点的左节点和右节点时,对栈先压入左节点再压入右节点,之后pop时我们就会先处理右节点。

Time Complexity - O(n),Space Complexity - O(n)。

/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new LinkedList<>();
if (root == null) return res;
Stack<TreeNode> stack = new Stack<>();
TreeNode node = root;
stack.push(node);
while (!stack.isEmpty()) {
node = stack.pop();
res.add(0, node.val);
if (node.left != null) stack.push(node.left);
if (node.right != null) stack.push(node.right);
}
return res;
}
}

Recursive:

Time Complexity - O(n),Space Complexity - O(n)。

/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
postorderTraversal(res, root);
return res;
} private void postorderTraversal(List<Integer> res, TreeNode root) {
if (root == null) return;
postorderTraversal(res, root.left);
postorderTraversal(res, root.right);
res.add(root.val);
}
}

Morris Traversal:

三刷终于学习了Morris Traversal。这里的Morris Traversal也使用的是Reversed Preorder traversal with LinkedList。也就是使用类似与Preorder traversal类似的代码,以及一个LinkedList,每次从表头插入结果。

因为Postorder和Preorder的对应关系,这里与Preorder Morris Traversal不同的就是,我们要找的不是左子树的predecessor,而是右子树中当前节点的successor,也就是当前节点右子树中最左边的元素。下面我们详述一下步骤。

  1. 依然先做一个root的reference - node,在node非空的情况对树进行遍历。当node.right为空的时候,我们将node.val从链表res头部插入,然后向左遍历左子树
  2. 假如右子树非空,则我们要找到当前节点在右子树中的succesor,简称succ,一样是两种情况:
    1. 首次访问succ,此时succ.left = null,我们把succ和当前node连接起来,进行succ.left = node。之后讲node.val从链表res头部插入,向右遍历node.right
    2. 否则,我们二次访问succ,这时succ.left = node,我们做一个还原操作,设succ.left = null,然后向左遍历node.left。因为node.val已经处理过,所以不要重复处理node.val.

Time Complexity - O(n),Space Complexity - O(1)。

/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new LinkedList<>();
TreeNode node = root, succ = null;
while (node != null) {
if (node.right == null) {
res.add(0, node.val);
node = node.left;
} else {
succ = node.right;
while (succ.left != null && succ.left != node) {
succ = succ.left;
}
if (succ.left == null) {
succ.left = node;
res.add(0, node.val);
node = node.right;
} else {
succ.left = null;
node = node.left;
}
}
}
return res;
}
}

Reference:

144. Binary Tree Preorder Traversal

https://leetcode.com/discuss/9736/accepted-code-with-explaination-does-anyone-have-better-idea

https://leetcode.com/discuss/71943/preorder-inorder-and-postorder-iteratively-summarization

https://leetcode.com/discuss/21995/a-very-concise-solution

https://leetcode.com/discuss/36711/solutions-iterative-recursive-traversal-different-solutions

145. Binary Tree Postorder Traversal的更多相关文章

  1. C++版 - LeetCode 145: Binary Tree Postorder Traversal(二叉树的后序遍历,迭代法)

    145. Binary Tree Postorder Traversal Total Submissions: 271797 Difficulty: Hard 提交网址: https://leetco ...

  2. 二叉树前序、中序、后序非递归遍历 144. Binary Tree Preorder Traversal 、 94. Binary Tree Inorder Traversal 、145. Binary Tree Postorder Traversal 、173. Binary Search Tree Iterator

    144. Binary Tree Preorder Traversal 前序的非递归遍历:用堆来实现 如果把这个代码改成先向堆存储左节点再存储右节点,就变成了每一行从右向左打印 如果用队列替代堆,并且 ...

  3. 【LeetCode】145. Binary Tree Postorder Traversal (3 solutions)

    Binary Tree Postorder Traversal Given a binary tree, return the postorder traversal of its nodes' va ...

  4. [LeetCode] 145. Binary Tree Postorder Traversal 二叉树的后序遍历

    Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary ...

  5. (二叉树 递归) leetcode 145. Binary Tree Postorder Traversal

    Given a binary tree, return the postorder traversal of its nodes' values. Example: Input: [1,null,2, ...

  6. LeetCode 145 Binary Tree Postorder Traversal(二叉树的兴许遍历)+(二叉树、迭代)

    翻译 给定一个二叉树.返回其兴许遍历的节点的值. 比如: 给定二叉树为 {1. #, 2, 3} 1 \ 2 / 3 返回 [3, 2, 1] 备注:用递归是微不足道的,你能够用迭代来完毕它吗? 原文 ...

  7. Java for LeetCode 145 Binary Tree Postorder Traversal

    Given a binary tree, return the postorder traversal of its nodes' values. For example: Given binary ...

  8. leetcode 145. Binary Tree Postorder Traversal ----- java

    Given a binary tree, return the postorder traversal of its nodes' values. For example:Given binary t ...

  9. LeetCode 145. Binary Tree Postorder Traversal 二叉树的后序遍历 C++

    Given a binary tree, return the postorder traversal of its nodes' values. Example: Input: [,,] \ / O ...

随机推荐

  1. Unity中使物体自动寻路的方法

    在做一个FPS游戏时,需要敌方自动找到玩家方位并向玩家移动,在查找资料(并走了不少坑)后,我试了三个方法,经测试,这三个方法都能实现自动寻路功能. 方法一:使用Mathf.Lerp()方法 代码很简单 ...

  2. [Guava官方文档翻译] 7. Guava的Immutable Collection(不可变集合)工具 (Immutable Collections Explained)

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3538666.html ,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体 ...

  3. Linux操作系统是如何工作的?破解操作系统的奥秘

    学号:SA12**6112 研究笔记: 1:计算机是怎么样工作的 2:用户态到内核态切换之奥秘解析 3:进程切换之奥秘解析 本博文主要是根据前3篇笔记来总结Linux内核的工作机制. 一:操作系统工作 ...

  4. c++中动态尾随内存的技巧和定位new

    c 和 c++ 最大的特点就是对内存的自由操作,数据类型,其实都是对内存的一种解释方式.C语言中常用的一个技巧就是尾随数据,网络编程中经常会用到这个特性, 特别是以前写完成端口的时候,这个特性肯定是会 ...

  5. WinForm应用程序退出的方法

    this.Close(); 只是关闭当前窗口,若不是主窗体的话,是无法退出程序的,另外若有托管线程(非主线程),也无法干净地退出. Application.Exit(); 强制所有消息中止,退出所有的 ...

  6. spl_autoload_register array参数

    spl_autoload_register (PHP 5 >= 5.1.2) spl_autoload_register — 注册给定的函数作为 __autoload 的实现 说明¶ bool  ...

  7. 无线WEP入侵注意事项

    1.工具bt3/bt4+spoonwep2(dep安装包)+U盘/VMwmare+无线网卡(可以笔记本内置)+UltraISO+unetbootin-windows-latest.exe+2.内置网卡 ...

  8. jQuery中模拟用户操作

    有时为了节省不想手动操作网页,但又想看到用户操作时的效果,可以用到jQuery提供的trigger方法.见下图代码 在不点击按钮时仍然想弹出this.value 我们只需要在后面加上.trigger( ...

  9. mysql alter的常用用法

    增加字段,并加注释: ALTER TABLE table_name ADD field_name field_type [not null|null|default value][comment '注 ...

  10. 进程,线程(thread)

    每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.进程也可能是整个程序或者是部分程序的动态执行.线程是一组指令的集合,或者是程序的特殊段, 它可以在程序里独立执行.也可把它理解为代码运行 ...