zoukankan      html  css  js  c++  java
  • 剑指 Offer 32

    在这里插入图片描述

    题目一 不分行从上到下打印二叉树

    队列 BFS

     使用广度优先可以遍历一幅有向图,树是图的一种特殊退化形式,从上到下按层遍历二叉树,从本质上来说就是广度优先遍历二叉树。
     实现BFS可以使用一个队列,每次从队列中取出一个节点,将其子节点加入到队列中,知道队列为空。
     由于题目要求输出一个数组,所以需要先知道树的节点数,因此可以使用递归先得到树的大小。
     另一种方案是使用java提供的ArrayList, 最后将ArrayList的元素赋值给数组。

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public int[] levelOrder(TreeNode root) {
            if(root == null) return new int[]{};
            Queue<TreeNode> queue = new LinkedList<>();
            queue.offer(root);
            int n = nodeNums(root);
            int[] ans = new int[n];
            int index = 0;
            // System.out.println(n);
            while(!queue.isEmpty()){
                TreeNode cur = queue.poll();
                ans[index++] = cur.val;
                if(cur.left != null) queue.offer(cur.left);
                if(cur.right != null) queue.offer(cur.right);
            }
            return ans;
        }
    
        private int N = 0;
    
        private int nodeNums(TreeNode node){
            if(node.left == null && node.right == null){
                return ++N;
            }else{
                ++N;
            }
            if(node.left != null)
                nodeNums(node.left);
            if(node.right != null)
                nodeNums(node.right);
            return  N;
        }
    }
    

    题目二 分行从上到下打印二叉树

    在这里插入图片描述

    解法一

    这题与第一题的不同在于要分行打印。第一种思路是从队列中每次取出当前层的所有元素加入list中,同时在队列中加入下一层所有元素,也就是取一层加下一层,知道最后队列为空

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public List<List<Integer>> levelOrder(TreeNode root) {
            if(root == null) return new ArrayList<>();
            Queue<TreeNode> queue = new LinkedList<>();
            queue.offer(root);
            List<List<Integer>> ans = new ArrayList<>();
            while(!queue.isEmpty()){
                int floorSize = queue.size();
                List<Integer> eachFloor = new ArrayList<>();
                for(int i = 0; i < floorSize; i++){
                    TreeNode cur = queue.poll();
                    if(cur.left != null) queue.offer(cur.left);
                    if(cur.right != null) queue.offer(cur.right);
                    eachFloor.add(cur.val);
                }
                ans.add(eachFloor);
            }
            return ans;
        }
    }
    

    解法二

     第二种思路还是从队列中每次取一个节点,然后将其子节点加入队列尾部。
    使用一个变量记录当前层剩余打印的节点数,使用另一个变量记录下一层的节点数。
     每次取出一个节点当前层剩余的节点减少1;取出一个节点后队列中加入其子节点,记录下一层节点数;当前层剩余节点为0时说明当前层以及取完,进入下一层。

    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public List<List<Integer>> levelOrder(TreeNode root) {
            if(root == null) return new ArrayList<>();
            Queue<TreeNode> queue = new LinkedList<>();
            queue.offer(root);
            List<List<Integer>> ans = new ArrayList<>();
             List<Integer> level = new ArrayList<>();
            int nextLevel = 0;//记录下一层的节点数
            int toBePrinted = 1;//当前层应打印的节点数
            while(!queue.isEmpty()){
                TreeNode cur = queue.poll();
                level.add(cur.val);
                toBePrinted--;
                if(cur.left != null){
                    ++nextLevel;
                    queue.offer(cur.left);
                }
                if(cur.right != null){
                    ++nextLevel;
                    queue.offer(cur.right);
                }
                if(toBePrinted == 0){
                    ans.add(level);
                    level = new ArrayList<Integer>();
                    toBePrinted = nextLevel;
                    nextLevel = 0;
                }
            }
            return ans;
        }
    }
    

    题目三 之字形打印二叉树

    在这里插入图片描述

    在这里插入图片描述
     以上面这颗二叉树为例,先打印节点3,然后将其子节点(9,20)保存到数据结构中。打印第二层时需要先打印20再打印9,所以是先进后出,可以使用“栈”保存(9,20)。打印第三层时从栈中先取出的是20,而打印需要先打印15,再打印7所以需要将7先压入栈,再将15压入栈。不同的层压栈顺序不一样所以需要两个栈交替使用。
     下面的解法为:

    • 定义两个栈:stack1保存“从左向右”打印的层节点,stack2保存从右向左打印的层节点
    • stack1中先压入根节点,弹出根节点后,将其子节点按顺序压入stack2
    • 从stack2中弹出所以节点并将其子节点按顺序压入stack1中
    • 以此类推知道两个栈都为空
    /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    class Solution {
        public List<List<Integer>> levelOrder(TreeNode root) {
            if(root == null) return new ArrayList();
            LinkedList<TreeNode> stack1 = new LinkedList<>();
            LinkedList<TreeNode> stack2 = new LinkedList<>();
            stack1.push(root);
            boolean nextDirect = true; //下一层打印的方向false:从左到右,true:从右到左
            List<List<Integer>> ans = new ArrayList<>();
            while(!stack1.isEmpty() || !stack2.isEmpty()){
                int size = nextDirect ? stack1.size() : stack2.size();
                List<Integer> level = new LinkedList<>();
                for(int i = 0; i < size; i++){
                    TreeNode node = nextDirect ? stack1.pop() : stack2.pop();
                    level.add(node.val);
                    if(nextDirect){
                        if(node.left != null)
                            stack2.push(node.left);
                        if(node.right != null)
                            stack2.push(node.right);
                    }else{
                        if(node.right != null)
                            stack1.push(node.right);
                        if(node.left != null)
                            stack1.push(node.left);
                    }
                }
                ans.add(level);
                nextDirect = !nextDirect;
            }
            return ans;
        }
    }
    

     相同的思路,一种更简洁的写法。定义一个数组存储两个栈:stack[0],stack[1];
     使用两个变量current和next来交替使用这两个栈。每次从当前栈中按每次一个取出所有元素,将这些元素根据当前打印顺序压入另一个栈中。当前栈中元素为空时,将两个栈进行交替。

    class Solution {
        public List<List<Integer>> levelOrder(TreeNode root) {
            if(root == null) return new ArrayList();
            LinkedList<TreeNode>[] stack = new LinkedList[]{new LinkedList(), new LinkedList()};
            stack[0].push(root);
            int current = 0;//标记打印顺序: 0:从左向右,1:从右向左
            int next = 1;//下一层
            List<List<Integer>> ans = new ArrayList<>();
            List<Integer> level = new ArrayList<>();
            while(!stack[0].isEmpty() || !stack[1].isEmpty()){
                TreeNode node = stack[current].pop();
                level.add(node.val);
                if(current == 0){
                    if(node.left != null)
                        stack[next].push(node.left);
                    if(node.right != null)
                        stack[next].push(node.right);
                }else{
                    if(node.right != null)
                        stack[next].push(node.right);
                    if(node.left != null)
                        stack[next].push(node.left);
                }
                if(stack[current].isEmpty()){
                    ans.add(level);
                    level = new ArrayList<>();
                    current = 1 - current;
                    next = 1 - next;
                }
            }
            return ans;
        }
    }
    
  • 相关阅读:
    java核心学习(二十七) 多线程---线程相关类
    java核心学习(二十六) 多线程---线程池
    java核心学习(二十五) 多线程---线程组和未处理的异常
    java核心学习(二十四) 多线程---线程通信
    java核心学习(二十三) 多线程---线程同步
    java核心学习(二十二) 多线程---线程控制
    模线性方程 poj2115
    求两个圆的重合面积+二分 hdu3264
    求多边形面积 HDU2036
    判断两直线是否相交 hdu1086
  • 原文地址:https://www.cnblogs.com/PythonFCG/p/13859958.html
Copyright © 2011-2022 走看看