[LeetCode 145] Binary Tree Postorder Traversal

来源:互联网 发布:java parseint方法 编辑:程序博客网 时间:2024/05/24 05:29

Question:

Given a binary tree, return the postorder traversal of its nodes' values.For example:Given binary tree {1,#,2,3},   1    \     2    /   3return [3,2,1]

Approach #1 Recursive [Accepted]

Detail Explanation
The first method to solve this problem is using recursive.
This is the classical method and straightforward.
we can define a helper function to implement recursion.
The java code is as follows:

Java

public class Solution {    public List<Integer> postorderTraversal(TreeNode root) {        List<Integer> res = new ArrayList<>();        helper(root, res);        return res;    }    public void helper(TreeNode root, List<Integer> res) {        if (root != null) {            if (root.left != null) {                helper(root.left, res);            }            if (root.right != null) {                helper(root.right, res);            }            res.add(root.val);        }    }}

Complexity Analysis

  • Time complexity : O(n). The time complexity is O(n) because the recursive function is T(n)=2T(n/2)+1.

  • Space complexity : The worst case is O(n), and the average case is O(log(n)) where n is number of nodes.
    a lot of people will have the question, why the worst case is O(n)?
    it is because the space complexity is related to the height of the tree when the tree is balanced, the height is O(log(n)), the worst case is O(n).


Approach #2 Iterating method using Stack

First Attempt: [Wrong Answer]
As other people, the first time do this question,
The first thing comes to my mind is
it is similar to the iterative method we did for Preorder Traversal and Inorder Traversal.
Here is my first attempt java code:

Java

public class Solution {    public List<Integer> postorderTraversal(TreeNode root) {        List<Integer> res = new ArrayList<>();        Stack<TreeNode> stack = new Stack<>();        TreeNode curr = root;        while (curr != null) {            stack.push(curr);            if (curr.right != null) {                stack.push(curr.right);            }            if (curr.left != null) {                curr = curr.left;            }            if (curr == null && !stack.isEmpty()) {                curr = stack.pop();                res.add(curr.val);            }        }        return res;    }}

why is doesn’t work?

Here is an Example:       1     /   \    2     3   / \  4   5Initial status: Stack[], res[], curr = 1;->: Push 1 into stack, Stack[1];->: Push 3 into stack, Stack[1,3], curr = 2;->: Push 2 into stack, Stack[1,3,2];->: Push 5 into stack, Stack[1,3,2,5], curr = 4;->: Push 4 into stack, Stack[1,3,2,5,4];->: Push 4 into stack, Stack[1,3,2,5,4], curr = null;->: Pop the Stack and add the poped val into res, res[4];->: Pop the Stack and add the poped val into res, res[4,5];->: Pop the Stack and add the poped val into res, res[4,5,2];    at this step, we find that the current node is updated by 2 which is a visited node.    if we continue, we will loop in the subtree [2,4,5] forever.

How to solve?
we have to know that the poped node is visited or not?

[ Method 1 ]: Using Two Stacks
Detail Explanation
First, let us do it in an easier method. Using two stacks.
Postorder traversal is like the Hanoi game. The problem is become how to design a strategy that makes sure the node’s order poped from stack is the post traversal order using 2 stacks?
You can try yourself as a practice.
Here is the strategy:
Step1. Initialize 2 stacks, Stack1 and Stack2;
Step2. Push current root into first stack;
Step3. While Stack1 is not empty
a pop Stack1 and push the poped node into stack2;
b Push popped node’s left into Stack1 if it is not NULL;
Push popped node’s right into Stack1 if it is not NULL;
Step4. While Stack2 is not empty
add the poped node into result list;

Here is an Example:       1     /   \    2     3   / \  4   5->1: Stack1[], Stack2[];->2: Push the root node into Stack1,        Stack1[1]        Stack2[];->3: the Stack1 is not empty so we go into the loop      step 3.a: Stack1[], Stack2[1];      step 3.b: Stack1[2,3], Stack2[1];->3: the Stack1 is not empty so we continue the loop      step 3.a: Stack1[2], Stack2[1, 3];->3: the Stack1 is not empty so we continue the loop      step 3.a: Stack1[], Stack2[1,3,2];      step 3.b: Stack1[4, 5], Stack2[1,3,2];->3: the Stack1 is not empty so we continue the loop      step 3.a: Stack1[4], Stack2[1,3,2,5];->3: the Stack1 is not empty so we continue the loop      step 3.a: Stack1[], Stack2[1,3,2,5,4];->3: the Stack1 is empty, quit the loop go to step4->4: pop the Stack2 one by one     the result is [4,5,2,3,1]

A comment

If you pay attention, you will find that Stack1 containing all the unprocessed node, and Stack2 is for the processed node.
When we finish processing the node, pop it from Stack1 and push it into Stack2

Java

class Solution {    public List<Integer> postorderTraversal(TreeNode root) {        List<Integer> res = new ArrayList<>();        Stack<TreeNode> stack1 = new Stack<>();        Stack<TreeNode> stack2 = new Stack<>();        if (root == null) {            return res;        }        stack1.push(root);        while (!stack1.isEmpty()) {            TreeNode temp = stack1.pop();            stack2.push(temp);            if (temp.left != null)                stack1.push(temp.left);            if (temp.right != null)                stack1.push(temp.right);        }        while (!stack2.isEmpty()) {            TreeNode temp = stack2.pop();            res.add(temp.val);        }        return res;    }}

Complexity Analysis

  • Time complexity : O(n)

  • Space complexity : O(n).

[ Method 2 ]: Using One Stack
Detail Explanation
the main problem is when we visit a TreeNode, we have to know that if the TreeNode has been visited or not? and how to check the visited TreeNode using just one stack?
The strategy is as follows:
Yu’s Coding Garden

Step1: Initializing, i.e, stack and result listStep2: Push the root node into the stack.Step3: while the stack is not empty, do:       if          a. the top node is a leaf node (no left && right children),                pop it.             or if the top node has been visited,                pop it.                (here we use a signed head to show the latest popped node, if the top node has child = the latest popped node, either left or right, it must have been visited.)       else          b. push the right child of the top node (if exists)          c. push the left child of the top node (if exists)Step4: return result list;
Here is an Example:       1     /   \    2     3   / \   /  4   5 6->1: Stack[]->2: Push the root node into Stack,        Stack[1]->3: the Stack is not empty so we go into the loop and the top node is 1;      step 3.b: push 3 into stack, Stack[1,3]      step 3.c: push 2 into stack, Stack[1,3,2]->3: the Stack is not empty so we continue the loop and the top node is 2;      step 3.b: push 5 into stack, Stack[1,3,2,5]      step 3.c: push 4 into stack, Stack[1,3,2,5,4]->3: the Stack is not empty so we continue the loop and the top node is 4;      step 3.a: node 4 is the leaf node so pop the stack, Stack[1,3,2,5];                add node 4 into result list, res[4];                update current node as 4;->3: the Stack is not empty so we continue the loop and the top node is 5      step 3.a: node 5 is the leaf node so pop the stack, Stack[1,3,2];                add node 5 into result list, res[4,5];                update current node as 5;->3: the Stack is not empty so we continue the loop and the top node is 2      //Please pay attention to this step, it helps us to find the visited node      step 3.a: top node is 2 and current node is 5                so node 2 is the visited node.                pop stack, Stack[1,3];                add node 2 into result list, res[4,5,2];                update current node as 2;->3: the Stack is empty so we continue the loop and the top node is 3      step 3.c push 6 into stack, Stack[1,3,6];->3: the Stack is not empty so we continue the loop and the top node is 6      step 3.a node 6 is the leaf node so we pop the stack, Stack[1,3];               add node 6 into result list, res[4,5,2,6];               update the current node as 6;->3: the stack is not empty so we continue the loop and the top node is 3      step 3.a node 3 is the visited node, pop the stack, Stack[1];               add node 3 into result list, res[4,5,2,6,3];               update current node as 3;->3: the stack is not empty so we continue the loop and the top node is 1     step 3.a node 1 is the visited node, pop the stack, Stack[];                              add node 1 into result list, res[4,5,2,6,3,1];                              update current node as 1;->4:     the result is res[4,5,2,6,3,1];

A comment

Pay attention that when we pop the stack?<br>1) when the node is the leaf child;2) when the node has been visited, but how can we know it?  Ans: we define 2 pointers, top which points to the top node on the stack;       head pointer point to the latest poped node.       if the head is the child of the top node, the top has been visited.

Java

class Solution {    public List<Integer> postorderTraversal(TreeNode root) {        List<Integer> res = new ArrayList<>();        Stack<TreeNode> stack = new Stack<>();        if (root == null)            return res;        stack.push(root);        TreeNode head = root;        while (!stack.isEmpty()) {            TreeNode top_Stack = stack.peek();            if ((top_Stack.left == null && top_Stack.right == null) || top_Stack.right == head || top_Stack.left == head) {                res.add(top_Stack.val);                stack.pop();                head = top_Stack;            } else {                if (top_Stack.right != null)                    stack.push(top_Stack.right);                if (top_Stack.left != null)                    stack.push(top_Stack.left);            }        }        return res;    }}

Complexity Analysis

  • Time complexity : O(n).

  • Space complexity : O(n).

Video Explanation for Using One Stack and Two Stack Methods

Iterative Method for Postorder Traversal


Approach #3 Morris Traversal [Accepted]

Detail Explanation
Morris Method to implement postorder traversal is a little tricky, and it is different from the Preorder Traversal and Inorder Traversal.
Moreover, this method needs to define a reverse function to help us to get the node’s value in post order.
This method we have to use a new data structure Threaded Binary Tree [Threaded binary tree]
(https://en.wikipedia.org/wiki/Threaded_binary_tree)
and the strategy is as follows:

Step1: Initialize a Temporary TreeNode as the temp, temp.left  = root, result list res[];Step2: set current node as temp;step3: while the curr is not NULL       a: if current node.left is NULL          set current node as current.right;       b: find the right most node in current left subtree as Predecessor Node;       c: IF (Predecessor Node.right child is NULL)              Set Predecessor Node.right as current node;              update current node as current node's left child;          ELSE (Predecessor Node.right child is not null, curr actually)              set Prodecessor Node's right as NULL;              using the reverse function which output is the reverse order of Nodes from curr.left to predecessor node;              add the output of reverse function into result list;              update curr as curr.right;Step4: Back to Step3;

For Example:
1.png
2.png
3.png
4.png
5.png
6.png
7.png
8.png
9.png
10.png
11.png
12.png
13.png
14.png
15.png
16.png
17.png
18.png
19.png
Java

/** * Definition for a binary tree node. * public class TreeNode { *     int val; *     TreeNode left; *     TreeNode right; *     TreeNode(int x) { val = x; } * } */class Solution{    public List<Integer> postorderTraversal(TreeNode root) {        List<Integer> res = new ArrayList<>();        TreeNode temp = new TreeNode(0);        temp.left = root;        TreeNode curr = temp;        TreeNode pro = null;        while (curr != null) {            if (curr.left == null) {                curr = curr.right;            } else {                pro = curr.left;                while (pro.right != null && pro.right != curr) {                    pro = pro.right;                }                if (pro.right == null) {                    pro.right = curr;                    curr = curr.left;                } else {                    this.addNode(curr.left, pro, res);                    pro.right = null;                    curr = curr.right;                }            }        }        return res;    }    public void reverse(TreeNode from, TreeNode to) {        if (from == to) {            return;        }        TreeNode x = from;        TreeNode y = from.right;        TreeNode z = null;        while (true) {            z = y.right;            y.right = x;            x = y;            y = z;            if (x == to) {                break;            }        }    }    public void addNode(TreeNode from, TreeNode to, List<Integer> res) {        reverse(from, to);        TreeNode temp = to;        while (true) {            res.add(temp.val);            if (temp == from)                break;            temp = temp.right;        }        reverse(to, from);    }}

Complexity Analysis

  • Time complexity : O(n). To prove that the time complexity is O(n),
    the biggest problem lies in finding the time complexity of finding the predecessor nodes of all the nodes in the binary tree.
    Intuitively, that complexity is O(nlogn), because to find the predecessor node for a single node related to the height of the tree.
    But in fact, finding the predecessor nodes for all nodes only needs O(n) time. Because n nodes in a Binary-Tree has n-1 edges, the whole processing for each edges up to 2 times, one is to locate a node, and the other is to find the predecessor node.
    So the complexity is O(n).a
  • Space complexity : O(1). The space complexity of Morris Traversal is O(1) because it just needs 2 “assisting” pointers.

Video Explanation

Morris Method for Postorder Traversal

Similar Questions

LeetCode 94: Binary Tree Inorder Traversal
Solution 94
LeetCode 144: Binary Tree Preorder Traversal
Solution 144

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 电脑ip地址连不上网怎么办 百度网盘资源打不开怎么办 百度网盘视频格式不支持怎么办 origin注册邮箱填错了怎么办 58同城手机输入不合法怎么办 银行卡密码输入错误三次怎么办 私密相册系统升级后打不开怎么办 由于志愿没填好孩子没书读怎么办 文具店不开了货怎么办 华为手机通讯录联系人重复怎么办 vcf文件用表格打开乱码怎么办 表格打出来太小怎么办 企业列入经营异常名录怎么办 小米电视滚动字幕模糊怎么办 海信电视浑的看不清怎么办 电视打开特别暗看不清怎么办 诈骗电话按了键怎么办 上海油电混合送沪牌以后怎么办? 车子被前夫砸了怎么办 老的标书丢了怎么办 拍牌照的标书掉了怎么办 上海拍到车牌后怎么办 杭州4s店车牌怎么办 天津车牌有指标想买车怎么办 上海大牌拍中了怎么办 买新车牌下不了怎么办 临沂上小学没报上名怎么办 早教中心倒闭了怎么办 企业税没交联系不上法人怎么办 企业被拉黑法人联系不到怎么办 支票根写错了怎么办 月结客户不付款怎么办 退市整理期过了怎么办 老板跑了财务负责人怎么办 在南京加入嘀嘀代驾怎么办 苹果盗刷支付宝怎么办 街电支付宝掉了怎么办 转转上号器没有苹果版的怎么办 安卓6不支持的应用怎么办 银行卡被存款机吞了怎么办 去银行卡存款机器故障怎么办