层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。
队列先进先出,符合一层一层遍历的逻辑,而是用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。

102. 二叉树的层序遍历

一旦出现层次遍历我们都可以使用队列作为辅助结构
迭代实现:

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode() {}
  8. * TreeNode(int val) { this.val = val; }
  9. * TreeNode(int val, TreeNode left, TreeNode right) {
  10. * this.val = val;
  11. * this.left = left;
  12. * this.right = right;
  13. * }
  14. * }
  15. */
  16. class Solution {
  17. public List<List<Integer>> levelOrder(TreeNode root) {
  18. //存放结果集
  19. LinkedList<List<Integer>> result = new LinkedList<>();
  20. if(root == null){
  21. return result;
  22. }
  23. //使用BFS
  24. //用一个队列存放元素
  25. Queue<TreeNode> q = new LinkedList<>();
  26. q.offer(root);
  27. // while 循环控制从上向下一层层遍历
  28. while (!q.isEmpty()){
  29. int size = q.size();//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数)
  30. // 记录这一层的节点值
  31. List<Integer> level = new LinkedList<>();
  32. // for 循环控制每一层从左向右遍历
  33. for (int i = 0; i < size; i++) {
  34. //临时节点暂存元素 弹出原值防止重复计算
  35. TreeNode temp = q.poll();
  36. //将这一层元素通过for循环逐个加进去
  37. level.add(temp.val);
  38. if (temp.left != null){
  39. q.offer(temp.left);//将左孩子加入队列,左右孩子加入队列也就能让我们继续遍历下一层,如果==null说明遍历到最后一层了
  40. }
  41. if(temp.right != null){
  42. q.offer(temp.right);//将右孩子加入队列
  43. }
  44. }
  45. result.add(level);//将这一层的元素追加到结果集
  46. }
  47. return result;
  48. }
  49. }

107. 二叉树的层序遍历 II

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        //存放结果集
        LinkedList<List<Integer>> result = new LinkedList<>();
        if(root == null){
            return result;
        }
        //使用DFS
        //用一个队列存放元素
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        // while 循环控制从上向下一层层遍历
        while (!q.isEmpty()){
            int size = q.size();//保存当前层的长度,然后处理当前层(十分重要,防止添加下层元素影响判断层中元素的个数)
            // 记录这一层的节点值
            List<Integer> level = new LinkedList<>();
            // for 循环控制每一层从左向右遍历
            for (int i = 0; i < size; i++) {
                //临时节点暂存元素 弹出原值防止重复计算
                TreeNode temp = q.poll();
                //将这一层元素通过for循环逐个加进去
                level.add(temp.val);
                if (temp.left != null){
                    q.offer(temp.left);//将左孩子加入队列,左右孩子加入队列也就能让我们继续遍历下一层,如果==null说明遍历到最后一层了
                }
                if(temp.right != null){
                    q.offer(temp.right);////将右孩子加入队列
                }
            }
            //result.add(level);//将这一层的元素追加到结果集
            result.addFirst(level);
        }

        return result;
    }
}

199. 二叉树的右视图

层序遍历的时候,判断是否遍历到单层的最后面的元素,如果是,就放进result数组中,随后返回result就可以了。

class Solution {

    /* BFS 层序遍历解法 */
    public List<Integer> rightSideView(TreeNode root) {
        List<Integer> res = new LinkedList<>();
        if (root == null) {
            return res;
        }
        // BFS 层序遍历,计算右侧视图
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        // while 循环控制从上向下一层层遍历
        while (!q.isEmpty()) {
            int sz = q.size();
            // 每一层头部就是最右侧的元素
            TreeNode last = q.peek();
            for (int i = 0; i < sz; i++) {
                TreeNode cur = q.poll();
                // 控制每一层从右向左遍历
                if (cur.right != null) {
                    q.offer(cur.right);
                }
                if (cur.left != null) {
                    q.offer(cur.left);
                }
            }
            // 每一层的最后一个节点就是二叉树的右侧视图
            res.add(last.val);
        }
        return res;
    }

    /* DFS 递归遍历解法 */
    List<Integer> res = new ArrayList<>();
    // 记录递归的层数
    int depth = 0;

    public List<Integer> rightSideView_DFS(TreeNode root) {
        traverse(root);
        return res;
    }

    // 二叉树遍历函数
    void traverse(TreeNode root) {
        if (root == null) {
            return;
        }
        // 前序遍历位置
        depth++;
        if (res.size() < depth) {
            // 这一层还没有记录值
            // 说明 root 就是右侧视图的第一个节点
            res.add(root.val);
        }
        // 注意,这里反过来,先遍历右子树再遍历左子树
        // 这样首先遍历的一定是右侧节点
        traverse(root.right);
        traverse(root.left);
        // 后序遍历位置
        depth--;
    }
}

637. 二叉树的层平均值

本题就是层序遍历的时候把一层求个总和在取一个均值。

class Solution {
    public List<Double> averageOfLevels(TreeNode root) {
        List<Double> res = new LinkedList<>();
        if (root == null) return res;

        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        while (!q.isEmpty()) {
            int size = q.size();
            // 记录当前层所有节点之和
            double sum = 0.0;
            for (int i = 0; i < size; i++) {
                TreeNode cur = q.poll();
                sum += cur.val;
                if (cur.left != null) {
                    q.offer(cur.left);
                }
                if (cur.right != null) {
                    q.offer(cur.right);
                }
            }
            // 记录当前行的平均值
            res.add( sum / size);
        }

        return res;
    }
}

429. N 叉树的层序遍历

使用队列保存每一层的所有节点,把队列里的所有节点出队列,然后把这些出去节点各自的子节点入队列

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
    public List<List<Integer>> levelOrder(Node root) {
        LinkedList<List<Integer>> result = new LinkedList<>();
        if (root == null){
            return result;
        }
        //队列
        Deque<Node> q = new LinkedList<>();
        q.offer(root);
        while (!q.isEmpty()){
            int size = q.size();
            //记录本层的元素
            List<Integer> level = new LinkedList<>();
            for (int i = 0; i < size; i++) {
                Node poll = q.pollFirst();
                level.add(poll.val);//添加第一个元素
                List<Node> children = poll.children;//所有的孩子节点
                if (children == null || children.size() == 0){
                    continue;//跳出这个循环
                }
                for (Node child : children) {
                    if (child != null){
                        q.offerLast(child);
                    }
                }
            }
            result.add(level);//添加本层元素
        }
        return result;
    }
}

小结 每一层的for循环都是为了遍历本层的所有元素,首先添加这层最左边的level.add(poll.val);然后遍历添加后面的q.offerLast(child)

大神:

/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
    public List<List<Integer>> levelOrder(Node root) {
        LinkedList<List<Integer>> result = new LinkedList<>();
        if (root == null){
            return result;
        }
        //队列
        Queue<Node> q = new LinkedList<>();
        q.offer(root);
        while (!q.isEmpty()){
            int size = q.size();
            LinkedList<Integer> level = new LinkedList<>();
            for (int i = 0; i < size; i++) {
                Node poll = q.poll();
                level.add(poll.val);
                q.addAll(poll.children);
            }
            result.add(level);
        }
        return result;
    }
}

515. 在每个树行中找最大值

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> largestValues(TreeNode root) {
        LinkedList<Integer> result = new LinkedList<>();
        if (root == null){
            return result;
        }
        //queue
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);

        while (!q.isEmpty()){
            int size = q.size();
            int max = Integer.MIN_VALUE;//记录当前层次的最大值
            for (int i = 0; i < size; i++) {
                TreeNode temp = q.poll();
                if (temp.left != null){
                    q.offer(temp.left);
                }
                if (temp.right!= null){
                    q.offer(temp.right);
                }
                //前面的两个if相当于循环遍历我们这一层的每一个值每一次取出来的值是temp.val
                if (max <= temp.val){
                    max = temp.val;
                }
            }
            result.add(max);
        }
        return result;
    }
}

116. 填充每个节点的下一个右侧节点指针

不会啊

class Solution {
    public Node connect(Node root) {
        if (root == null) {
            return root;
        }

        // 初始化队列同时将第一层节点加入队列中,即根节点
        Queue<Node> queue = new LinkedList<Node>(); 
        queue.add(root);

        // 外层的 while 循环迭代的是层数
        while (!queue.isEmpty()) {

            // 记录当前队列大小
            int size = queue.size();

            // 遍历这一层的所有节点
            for (int i = 0; i < size; i++) {

                // 从队首取出元素
                Node node = queue.poll();

                // 连接
                if (i < size - 1) {
                    node.next = queue.peek();
                }

                // 拓展下一层节点
                if (node.left != null) {
                    queue.add(node.left);
                }
                if (node.right != null) {
                    queue.add(node.right);
                }
            }
        }

        // 返回根节点
        return root;
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/solution/tian-chong-mei-ge-jie-dian-de-xia-yi-ge-you-ce-2-4/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

另一种思路:
你可以把二叉树的相邻节点抽象成一个「三叉树节点」,这样二叉树就变成了一棵「三叉树」,然后你去遍历这棵三叉树,把每个「三叉树节点」中的两个节点连接就行了:

class Solution {
    // 主函数
    public Node connect(Node root) {
        if (root == null) return null;
        // 遍历「三叉树」,连接相邻节点
        traverse(root.left, root.right);
        return root;
    }

    // 三叉树遍历框架
    void traverse(Node node1, Node node2) {
        if (node1 == null || node2 == null) {
            return;
        }
        /**** 前序位置 ****/
        // 将传入的两个节点穿起来
        node1.next = node2;

        // 连接相同父节点的两个子节点
        traverse(node1.left, node1.right);
        traverse(node2.left, node2.right);
        // 连接跨越父节点的两个子节点
        traverse(node1.right, node2.left);
    }
}
// 详细解析参见:
// https://labuladong.gitee.io/article/?qno=116

104. 二叉树的最大深度

使用广度优先:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int maxDepth(TreeNode root) {
        int max = 0;
        if (root == null) return max;

        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);

        while (!q.isEmpty()){
            int size = q.size();
            //下面用for循环一样
            while (size > 0){
                TreeNode node = q.poll();
                if (node.left != null)  q.offer(node.left);
                if (node.right != null) q.offer(node.right);
                size--;
            }
            max++;
        }
        return max;
    }
}

深度优先:

class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        } else {
            int leftHeight = maxDepth(root.left);
            int rightHeight = maxDepth(root.right);
            return Math.max(leftHeight, rightHeight) + 1;
        }
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/solution/er-cha-shu-de-zui-da-shen-du-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

111. 二叉树的最小深度

DFS:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
   public int minDepth(TreeNode root) {
        if (root == null) {
            return 0;
        } else if (root.left == null) {
            return minDepth(root.right) + 1;
        } else if (root.right == null) {
            return minDepth(root.left) + 1;
        } else {
            return Math.min(minDepth(root.right), minDepth(root.left)) + 1;
        }
    }
}

BFS:
需要注意的是,只有当左右孩子都为空的时候,才说明遍历的最低点了。如果其中一个孩子为空则不是最低点

class Solution {
    public int minDepth(TreeNode root) {
        if (root == null) return 0;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        // root 本身就是一层,depth 初始化为 1
        int depth = 1;

        while (!q.isEmpty()) {
            int sz = q.size();
            /* 遍历当前层的节点 */
            for (int i = 0; i < sz; i++) {
                TreeNode cur = q.poll();
                /* 判断是否到达叶子结点 */
                if (cur.left == null && cur.right == null)
                    return depth;
                /* 将下一层节点加入队列 */
                if (cur.left != null)
                    q.offer(cur.left);
                if (cur.right != null)
                    q.offer(cur.right);
            }
            /* 这里增加步数 */
            depth++;
        }
        return depth;
    }
}
// 详细解析参见:
// https://labuladong.gitee.io/article/?qno=111