题目链接

题目大意:后序遍历二叉树。

法一:普通递归,只是这里需要传入一个list来存储遍历结果。代码如下(耗时1ms):

  1. public List<Integer> postorderTraversal(TreeNode root) {
  2. List<Integer> list = new ArrayList<Integer>();
  3. list = dfs(root, list);
  4. return list;
  5. }
  6. public static List<Integer> dfs(TreeNode root, List<Integer> list) {
  7. if(root == null) {
  8. return list;
  9. }
  10. else {
  11. list = dfs(root.left, list);
  12. list = dfs(root.right, list);
  13. list.add(root.val);
  14. return list;
  15. }
  16. }

法二(借鉴):后序遍历顺序是“左右根”,这里将其反过来遍历,也就是“根右左”,然后将遍历结果反转返回即可。这里用到了LinkedList.addFirst()方法,即将值插到链表头部。(addLast()方法与add()方法一样是插到链表尾部)。这里也可以用ArrayList.add(),在最后再调用Collections.reverse(list)方法即可。此方法代码简单,但不是很好想。代码如下(耗时1ms):

  1. public List<Integer> postorderTraversal(TreeNode root) {
  2. LinkedList<Integer> list = new LinkedList<Integer>();
  3. if(root == null) {
  4. return list;
  5. }
  6. Stack<TreeNode> stack = new Stack<TreeNode>();
  7. stack.push(root);
  8. TreeNode tmp = null;
  9. while(!stack.isEmpty()) {
  10. tmp = stack.pop();
  11. list.addFirst(tmp.val);
  12. if(tmp.left != null) {
  13. stack.push(tmp.left);
  14. }
  15. if(tmp.right != null) {
  16. stack.push(tmp.right);
  17. }
  18. }
  19. return list;
  20. }

法三(借鉴):普通后序非递归遍历,这里用一个辅助栈来标记结点是否已经访问右结点,如果已经访问右结点,则将根值加入list中,否则访问右结点压栈。因为有两个栈要压栈出栈,耗时较长。也可以在TreeNode结点中加入一个标记属性flag来标记是否访问过右结点,这样就不需要辅助栈了,时间应该会快一些。代码如下(耗时2ms):

  1. public List<Integer> postorderTraversal(TreeNode root) {
  2. List<Integer> list = new ArrayList<Integer>();
  3. if(root == null) {
  4. return list;
  5. }
  6. Stack<TreeNode> stackNode = new Stack<TreeNode>();
  7. //0表示右结点未访问,1表示右结点已访问
  8. Stack<Integer> stackFlag = new Stack<Integer>();
  9. stackNode.push(root);
  10. stackFlag.push(0);
  11. TreeNode tmp = root.left;//已压栈,则访问其左结点
  12. while(!stackNode.isEmpty()) {
  13. while(tmp != null) {
  14. stackNode.push(tmp);
  15. stackFlag.push(0);
  16. tmp = tmp.left;
  17. }
  18. if(stackFlag.peek() == 0) {
  19. //右结点未访问,则访问右结点
  20. tmp = stackNode.peek().right;
  21. stackFlag.pop();
  22. stackFlag.push(1);//将访问右结点状态置1
  23. }
  24. else {
  25. //右结点已访问,则将根结点加入list队列,并将根节点弹出
  26. list.add(stackNode.pop().val);
  27. stackFlag.pop();//弹出根节点状态值
  28. }
  29. }
  30. return list;
  31. }

法四(借鉴):保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子,则可以直接访问它;或者P存 在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了 每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。这个比法二还要难理解,特别是要先压right再压left。代码如下(耗时2ms):

  1. public List<Integer> postorderTraversal(TreeNode root) {
  2. List<Integer> list = new ArrayList<Integer>();
  3. if(root == null) {
  4. return list;
  5. }
  6. Stack<TreeNode> stack = new Stack<TreeNode>();
  7. stack.push(root);
  8. TreeNode pre = null, cur = null;
  9. while(!stack.isEmpty()) {
  10. cur = stack.peek();//判断当前结点情况,所以用peek不用pop
  11. if((cur.left == null && cur.right == null) ||
  12. (pre != null && (pre == cur.left || pre == cur.right))) {
  13. //如果当前结点没有左右孩子则直接弹出当前结点
  14. //如果当前结点的左右孩子都已经访问完则弹出当前结点
  15. list.add(cur.val);
  16. pre = cur;
  17. stack.pop();
  18. }
  19. else {
  20. //注意这里一定要先压right再压left,因为栈的先进后出的原则,到时候会先弹出left再弹出right,这样的顺序才正确。
  21. if(cur.right != null) {
  22. stack.push(cur.right);
  23. }
  24. if(cur.left != null) {
  25. stack.push(cur.left);
  26. }
  27. }
  28. }
  29. return list;
  30. }

法五(借鉴):最接近先序、中序非递归遍历的方法,先压左结点再判断栈顶元素。代码如下(耗时2ms):

  1. public List<Integer> postorderTraversal(TreeNode root) {
  2. List<Integer> list = new ArrayList<Integer>();
  3. if(root == null) {
  4. return list;
  5. }
  6. Stack<TreeNode> stack = new Stack<TreeNode>();
  7. stack.push(root);
  8. TreeNode pre = null, cur = root.left;
  9. while(!stack.isEmpty()) {
  10. while(cur != null) {
  11. stack.push(cur);
  12. cur = cur.left;
  13. }
  14. //判断栈顶结点
  15. cur = stack.peek();
  16. //判断是否访问栈顶结点
  17. if(cur.right != null && pre != cur.right) {
  18. //如果不是从右孩子返回,即还未访问右孩子,则访问
  19. cur = cur.right;
  20. }
  21. else {
  22. //如果没有右孩子或右孩子已经访问过,则直接弹出当前节点进行访问
  23. list.add(cur.val);
  24. stack.pop();
  25. //记录当前访问的结点
  26. pre = cur;
  27. //将当前结点赋空
  28. cur = null;
  29. }
  30. }
  31. return list;
  32. }

145.Binary Tree Postorder Traversal---二叉树后序非递归遍历的更多相关文章

  1. [Leetcode] Binary tree postorder traversal二叉树后序遍历

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

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

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

  3. LeetCode:145_Binary Tree Postorder Traversal | 二叉树后序遍历 | Hard

    题目:Binary Tree Postorder Traversal 二叉树的后序遍历,题目要求是采用非递归的方式,这个在上数据结构的课时已经很清楚了,二叉树的非递归遍历不管采用何种方式,都需要用到栈 ...

  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二叉树的后序遍历 (C++)

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

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

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

  7. 145 Binary Tree Postorder Traversal 二叉树的后序遍历

    给定一棵二叉树,返回其节点值的后序遍历.例如:给定二叉树 [1,null,2,3],   1    \     2    /   3返回 [3,2,1].注意: 递归方法很简单,你可以使用迭代方法来解 ...

  8. LeetCode OJ:Binary Tree Postorder Traversal(后序遍历二叉树)

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

  9. 94.Binary Tree Inorder Traversal---二叉树中序非递归遍历

    题目链接 题目大意:中序遍历二叉树.先序见144,后序见145. 法一:DFS,没啥说的,就是模板DFS.代码如下(耗时1ms): public List<Integer> inorder ...

随机推荐

  1. ICPCCamp 2017 I Coprime Queries

    给出一个长度为\(n\)的正整数序列\(a\),\(m\)次询问\(l,r,x\),问\(max\{i|i\in[l,r],gcd(a_i,x)=1\}\). \(n,m,a_i\le 10^5\). ...

  2. day4 列表 增删改查 元组

    增lis=["a","b","c",5,7,4]lis.append("s")#在列表的末尾追加lis.extend(& ...

  3. Java操作excel(POI)

    由于在项目中使用了将excel数据导入到数据库.在这里分享一下. 这里使用的POI方式,支持两种格式(xls,xlsx) package com.entity; import java.io.File ...

  4. 洛谷P4608 [FJOI2016]所有公共子序列问题 【序列自动机 + dp + 高精】

    题目链接 洛谷P4608 题解 建个序列自动机后 第一问暴搜 第二问dp + 高精 设\(f[i][j]\)为两个序列自动机分别走到\(i\)和\(j\)节点的方案数,答案就是\(f[0][0]\) ...

  5. 第13章 MySQL服务器的状态--高性能MySQL学习笔记

    13.1 系统变量 -- 服务器配置变量 MySQL通过SHOW VARIABLES  SQL命令显示许多系统变量. 13.2 状态变量--SHOW STATUS SHOW STATUS 命令会在一个 ...

  6. PID控制算法的C语言实现十 专家PID与模糊PID的C语言实现

    本节是PID控制算法的C语言实现系列的最后一节,前面8节中,已经分别从PID的实现到深入的过程进行了一个简要的讲解,从前面的讲解中不难看出,PID的控制思想非常简单,其主要问题点和难点在于比例.积分. ...

  7. Codeforces Round #340 (Div. 2) E 莫队+前缀异或和

    E. XOR and Favorite Number time limit per test 4 seconds memory limit per test 256 megabytes input s ...

  8. POJ 3260 完全背包+多重背包+思维

    传送门:https://vjudge.net/problem/20465/origin 题意:你有n种钞票,面值为c[i],数量为v[i],便利店老板有无数张面值为c[i]的钞票,问你买一个价值为T的 ...

  9. ubuntu 安装微信开发者工具

    https://github.com/cytle/wechat_web_devtools 实测:64位  32位的可以... 参考命令; 2030 sudo apt-get install wine1 ...

  10. 获取Session和request方法

    action中的几种写法 //第一种很少用public class LoginAction1 extends ActionSupport {        private Map request;   ...