剑指offer面试题牛客_二叉树_按之字形顺序打印二叉树(java版)

welcome to my blog

剑指offer面试题牛客_二叉树_按之字形顺序打印二叉树(java版):

题目描述

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

第四次做; 使用两个栈实现; 优秀案例如下
      1
     / \
    2   3
   /     \
  4       5
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root==null)
            return res;
        //
        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();
        stack1.add(root);
        //true表示在偶数层, 根节点是第0层
        boolean flag = true;
        while(!stack1.isEmpty() || !stack2.isEmpty()){
            res.add(new ArrayList<>());
            if(flag==true){
                while(!stack1.isEmpty()){
                    TreeNode cur = stack1.pop();
                    res.get(res.size()-1).add(cur.val);
                    if(cur.left!=null)
                        stack2.push(cur.left);
                    if(cur.right!=null)
                        stack2.push(cur.right);
                }
                flag=false;
            }
            else{
                while(!stack2.isEmpty()){
                    TreeNode cur = stack2.pop();
                    res.get(res.size()-1).add(cur.val);
                    if(cur.right!=null)
                        stack1.push(cur.right);
                    if(cur.left!=null)
                        stack1.push(cur.left);
                }
                flag=true;
            }
        }
        return res;
    }
}

思路

  • 使用两个栈
  • 处理奇数层节点时, 先将其左孩子(如果有的话)压栈, 再将其右孩子(如果有的话)压栈
  • 处理偶数层节点时, 先将其右孩子(如果有的话)压栈, 再将其左孩子(如果有的话)压栈
  • 将左右孩子节点压栈的时候, 一定要先判断是否有左右孩子,
    开始没有判断, 导致压入了null, 调用.val报错
第三次做, 感觉第二次的逻辑更严密一点点
import java.util.ArrayList;
import java.util.Stack;

public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        if(pRoot==null)
            return res;
        Stack<TreeNode> s1 = new Stack<>();
        Stack<TreeNode> s2 = new Stack<>();
        s1.push(pRoot);
        TreeNode curr;
        while(!s1.isEmpty() || !s2.isEmpty()){
            res.add(new ArrayList<Integer>());
            if(!s1.isEmpty()){
                while(!s1.isEmpty()){
                    curr = s1.pop();
                    res.get(res.size()-1).add(curr.val);
                    if(curr.left!=null)
                        s2.push(curr.left);
                    if(curr.right!=null)
                        s2.push(curr.right);
                }
            }
            else if(!s2.isEmpty()){
                while(!s2.isEmpty()){
                    curr = s2.pop();
                    res.get(res.size()-1).add(curr.val);
                    if(curr.right!=null)
                        s1.push(curr.right);
                    if(curr.left!=null)
                        s1.push(curr.left);
                }
            }
        }
        return res;
    }

}
第二次做, 使用两个栈实现
import java.util.ArrayList;
import java.util.Stack;

public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        if(pRoot==null)
            return res;
        Stack<TreeNode> s1 = new Stack<>();
        Stack<TreeNode> s2 = new Stack<>();
        s1.push(pRoot);
        TreeNode curr;
        while(!s1.isEmpty() || !s2.isEmpty()){
            ArrayList<Integer> temp = new ArrayList<>();
            if(!s1.isEmpty()){
                while(!s1.isEmpty()){
                    curr = s1.pop();
                    temp.add(curr.val);
                    if(curr.left!=null)
                        s2.push(curr.left);
                    if(curr.right!=null)
                        s2.push(curr.right);
                }
                res.add(temp);
            }
            else{
                while(!s2.isEmpty()){
                    curr = s2.pop();
                    temp.add(curr.val);
                    if(curr.right!=null)
                        s1.push(curr.right);
                    if(curr.left!=null)
                        s1.push(curr.left);
                }
                res.add(temp);
            }
        }
        return res;
    }

}
循环版
import java.util.ArrayList;
import java.util.Stack;

public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        /*
        思路: 使用两个栈实现,
        处理奇数层的节点时,先将其左孩子压栈, 再将其右孩子压栈
        处理偶数层的节点时,先将其右孩子压栈, 再将其左孩子压栈
        */
        ArrayList<ArrayList<Integer>> alal = new ArrayList<ArrayList<Integer>>();
        //input check
        if(pRoot == null) 
            return alal;
        //execute
        Stack<TreeNode> s1 = new Stack<TreeNode>();
        Stack<TreeNode> s2 = new Stack<TreeNode>();
        s1.push(pRoot); //先将根节点压栈
        TreeNode curr;
        int flag=1;
        while(true){
            if(s1.isEmpty() && s2.isEmpty()) 
                break; //遍历完毕, 调出循环
            if(flag==1){ //当前处理奇数层的节点
                alal.add(new ArrayList<Integer>()); //为当前层添加集合
                while(!s1.isEmpty()){
                    curr = s1.pop(); //出栈
                    alal.get(alal.size()-1).add(curr.val); // 打印
                    if(curr.left != null) 
                        s2.push(curr.left); //如果有左孩子的话, 左孩子入栈 
                    if(curr.right != null) 
                        s2.push(curr.right); //如果有右孩子的话,右孩子入栈
                }
                flag = 1 - flag;
            }
            else{
                alal.add(new ArrayList<Integer>());
                while(!s2.isEmpty()){
                    curr = s2.pop();
                    alal.get(alal.size()-1).add(curr.val);
                    if(curr.right != null) 
                        s1.push(curr.right); //如果有右孩子的话, 右孩子入栈
                    if(curr.left != null) 
                        s1.push(curr.left); //如果有左孩子的话, 左孩子入栈
                }
                flag = 1 - flag;
            }
        }
        return alal;
    }
}
递归版, 不如循环版直观易懂
  • 处理完当前层所有的节点后, 才能对下一层的节点进行递归调用
  • 比较难理解的是递归函数中的Core(tn.left, layer+1, s1, s2, alal); Core(tn.right, layer+1, s1, s2, alal);这两句的顺序不影响结果. 其实不难理解, 处理完某个奇数层之后, 通过Core处理接下来的偶数层节点, 由于在处理奇数层节点时,把当前偶数层节点的节点排好序放在集合里了,所以Core不会影响当前层的打印顺序,Core做的是处理已经安排好的栈s2, 有了安排好的栈s2, Core就能根据s2中的顺序安排好s1.
  • 总之, 递归函数中的形参TreeNode p, 只是用来判断p是否为空的, 不会对处理顺序产生影响
  • 处理顺序全靠两个栈,以及压栈顺序决定
import java.util.ArrayList;
import java.util.Stack;
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> alal = new ArrayList<ArrayList<Integer>>();
        //input check
        if(pRoot==null)
            return alal;
        //execute
        Stack<TreeNode> s1 = new Stack<TreeNode>();
        Stack<TreeNode> s2 = new Stack<TreeNode>();
        s1.push(pRoot);
        Core(pRoot, 1, s1, s2, alal);
        return alal;
    }
    // 递归函数逻辑: 根据当前的层数, 将对应栈中的节点弹出, 并将节点对应的值加入对应的集合中, 再递归处理左右孩子
    public void Core(TreeNode p, int layer, Stack<TreeNode> s1, Stack<TreeNode> s2, ArrayList<ArrayList<Integer>> alal){
        if(p == null) return;
        TreeNode curr;
        if(layer%2==1){ //当前在奇数层
            if(alal.size() < layer)
                alal.add(new ArrayList<Integer>());
            ArrayList<TreeNode> al = new ArrayList<TreeNode>();
            while(!s1.isEmpty()){
                curr = s1.pop();
                al.add(curr);
                alal.get(layer-1).add(curr.val);
                if(curr.left != null)
                    s2.push(curr.left);
                if(curr.right != null)
                    s2.push(curr.right);
            }
            for(TreeNode tn:al){//处理完当前层所有的节点后, 才能对下一层的节点进行递归调用
                Core(tn.left, layer+1, s1, s2, alal);
                Core(tn.right, layer+1, s1, s2, alal);
            }

        }
        else{ //当前在偶数层
            if(alal.size() < layer)
                alal.add(new ArrayList<Integer>());
            ArrayList<TreeNode> al = new ArrayList<TreeNode>();
            while(!s2.isEmpty()){
                curr = s2.pop();
                al.add(curr);
                alal.get(layer-1).add(curr.val);
                if(curr.right != null)
                    s1.push(curr.right);
                if(curr.left != null)
                    s1.push(curr.left);
            }
            for(TreeNode tn:al){//处理完当前层所有的节点后, 才能对下一层的节点进行递归调用
                Core(tn.left, layer+1, s1, s2, alal);
                Core(tn.right, layer+1, s1, s2, alal);
            }
        }
    }

}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值