leetcode binary-tree-postorder-traversal(Java)(四种解法)

leetcode题目

binary-tree-postorder-traversal

题目描述

  • 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?

思路

1、递归
2、两个栈倒换元素实现
3、栈、线性表倒换元素后反转线性表
4、单个栈处理,有条件元素出栈

代码

package com.my.test.leetcode.tree;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Stack;

/**
 * 题目:
 * binary-tree-postorder-traversal 
 *
 * 题目描述:
 * 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?
 * 
 */
public class PostOrderTree {

    static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int x) { val = x; }
    }

    /**
     * 递归解法(栈溢出/内存溢出 风险,不推荐)
     */
    public ArrayList<Integer> postorderRecursiveTraversal(TreeNode root) {
        ArrayList<Integer> retList = new ArrayList<>();
        if (root == null) {
            return retList;
        }
        postorderRecursiveTraversal(root, retList);
        return retList;
    }
    
    private void postorderRecursiveTraversal(TreeNode root, ArrayList<Integer> lst) {
        if (root == null) {
            return;
        }
        postorderRecursiveTraversal(root.left, lst);
        postorderRecursiveTraversal(root.right, lst);
        lst.add(root.val);
    }
    
    /**
     * 思路:
     * 1、使用两个栈来实现后续遍历
     * 2、一个栈s1初始化只有头节点,按照左右顺序把孩子节点入栈
     * 3、另一个栈s2在s1元素出栈时把元素入栈,入栈顺序为右左,则出栈顺序为左右孩子,最后为中间节点。
     */
    public ArrayList<Integer> postorderTraversalByTwoStack(TreeNode root) {
        ArrayList<Integer> retList = new ArrayList<>();
        if (root == null) {
            return retList;
        }
        
        // 初始化s1 s2
        Stack<TreeNode> s1 = new Stack<>();
        s1.push(root);
        
        Stack<TreeNode> s2 = new Stack<>();
        TreeNode curNode;
        
        // s1中节点弹出后,压入s2,左右孩子节点依次压入s1
        while (!s1.empty()) {
            curNode = s1.pop();
            s2.push(curNode);
            
            // 依次压入左右孩子,s1弹出元素顺序为右左,s2入栈顺序为右左,保证s2出栈顺序为左右
            if (curNode.left != null) {
                s1.push(curNode.left);
            }
            if (curNode.right != null) {
                s1.push(curNode.right);
            }
        }
        
        // s2中元素出栈,转移到retList
        while (!s2.empty()) {
            retList.add(s2.pop().val); 
        }
        
        return retList;
    } 
    
    /**
     * 思路(巧妙解法,其实与上述思路类似):
     * 1、先序遍历的变体--中右左顺序遍历树,结果入ArrayList
     * 2、ArrayList反转
     */
    public ArrayList<Integer> postorderTraversalByRightLeftPreOrder(TreeNode root) {
        ArrayList<Integer> retList = new ArrayList<>();
        if (root == null) {
            return retList;
        }
        
        // 初始化栈,便于先序遍历(中右左顺序)二叉树
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        
        TreeNode curNode;
        // 先序的变体-中右左遍历,结果保存到retList,然后反转retList
        while (!stack.empty()) {
            curNode = stack.pop();
            retList.add(curNode.val);
            
            // 先左后右添加 保证栈弹出顺序是右左,在反转retList后,整体顺讯为左右中后续遍历
            // 添加左孩子
            if (curNode.left != null) {
                stack.push(curNode.left);
            }
            // 添加右孩子
            if (curNode.right != null) {
                stack.push(curNode.right);
            }
        }
        // 反转ArrayList
        Collections.reverse(retList);
        return retList;
    }
    
    /**
     * 思路:
     * 1、初始一个栈,有根节点元素
     * 2、如果元素的左右孩子节点都为空,则出栈;上次出栈的是元素的右孩子,则出栈;上次出栈的是元素的左孩子、并且元素的右孩子为空,则出栈
     * 3、不满足出栈条件,则添加右孩子,再添加左孩子
     */
    public ArrayList<Integer> postorderTraversal(TreeNode root) {
        ArrayList<Integer> retList = new ArrayList<>();
        if (root == null) {
            return retList;
        }
        
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        
        TreeNode pre = null;
        TreeNode curNode;
        
        while (!stack.empty()) {
            curNode = stack.peek();
            if (hasNoChilds(curNode) || IsPrePopLeftChildAndNoRightChild(curNode, pre) || IsPrePopRightChild(curNode, pre)) {
                // 弹出元素
                pre = stack.pop();
                retList.add(pre.val);
            } else {
                // 添加右孩子
                if (curNode.right != null) {
                    stack.push(curNode.right);
                }
                // 添加左孩子
                if (curNode.left != null) {
                    stack.push(curNode.left);
                }
            }
        }
        return retList;
    }
    
    private boolean hasNoChilds(TreeNode node) {
        return node.left == null && node.right == null;
    }
    
    private boolean IsPrePopLeftChildAndNoRightChild(TreeNode root, TreeNode prePop) {
        return root.left == prePop && root.right == null;
    }
    
    private boolean IsPrePopRightChild(TreeNode root, TreeNode prePop) {
        return prePop != null && root.right == prePop;
    }
    
    public static void main(String[] args) {
        TreeNode root = new TreeNode(1);
        TreeNode right = new TreeNode(2);
        root.right = right;
        TreeNode left = new TreeNode(3);
        right.left = left;
        System.out.println(new PostOrderTree().postorderRecursiveTraversal(root));
        System.out.println(new PostOrderTree().postorderTraversalByTwoStack(root));
        System.out.println(new PostOrderTree().postorderTraversalByRightLeftPreOrder(root));
        System.out.println(new PostOrderTree().postorderTraversal(root));
        
        TreeNode root1 = new TreeNode(3);
        TreeNode left1 = new TreeNode(1);
        root1.left = left1;
        TreeNode right1 = new TreeNode(2);
        root1.right = right1;
        System.out.println(new PostOrderTree().postorderRecursiveTraversal(root1));
        System.out.println(new PostOrderTree().postorderTraversalByTwoStack(root1));
        System.out.println(new PostOrderTree().postorderTraversalByRightLeftPreOrder(root1));
        System.out.println(new PostOrderTree().postorderTraversal(root1));
    }
}

猜你喜欢

转载自blog.csdn.net/zangdaiyang1991/article/details/89323605