Leetcode 二叉树的层序遍历

算法思想:

  • 层序遍历是指从根节点开始,按层次逐层遍历二叉树的所有节点。每一层从左到右依次访问节点,然后再进入下一层。
  • 使用队列这种数据结构来实现层序遍历,因为队列遵循**先进先出(FIFO)**的原则,正好适合处理逐层的遍历过程。
  • 主要思路是:
    1. 从根节点开始,将它加入队列。
    2. 逐层访问队列中的每个节点,并将该节点的子节点(如果有的话)加入到队列中。
    3. 每次完成一层的遍历后,将这一层的所有节点值存储到结果列表中,继续处理下一层。
java 复制代码
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        if(root == null) {
            return result;
        }
        queue.offer(root);
        while(!queue.isEmpty()) {
            int currentLevelnum = queue.size(); //当前层需要处理的节点个数
            List<Integer> currentLevel = new ArrayList<>();  //初始化当前层节点不能放在while循环外部!!
            for(int i = 0; i < currentLevelnum; ++i) {
                TreeNode node = queue.poll(); //这里只是出队了,而出队节点在二叉树中的结构并未改变。
                currentLevel.add(node.val);
                if(node.left != null) {
                    queue.offer(node.left);
                }
                if(node.right != null) {
                    queue.offer(node.right);
                }
            }
            result.add(currentLevel);
        }
        return result;
    }
}

为什么List<Integer> currentLevel = new ArrayList<>(); 的位置放到while循环外部,会得到错误的结果?

来分析一下为什么会这样。

问题的根源:

  1. currentLevel 的复用问题 :在你的代码中,currentLevel 只在方法开始时被初始化一次,然后在后续的每一层遍历中,所有层的节点值都会被添加到同一个 currentLevel 列表中。
    • 因为你在 while 循环外部初始化了 currentLevel,当你进行多层遍历时,所有层的节点值都会被不断添加到同一个 currentLevel 列表,而不是为每一层创建新的列表。
    • 当你将 currentLevel 添加到 result 中时,实际上你添加的是同一个 currentLevel 的引用。即使在后续层继续向这个列表添加元素,result 中的所有层都会指向同一个列表,最终导致所有层的结果被错误地合并在一起。

具体错误结果的表现:

  • 假设你有一个三层的树结构。在第一次遍历第一层时,currentLevel 里保存的是第一层的节点值,例如 [3]
  • 然后遍历第二层时,第二层的节点值(如 [9, 20])也被添加到了同一个 currentLevel 中,因此 currentLevel 变成 [3, 9, 20]
  • 最后,第三层的节点值(如 [15, 7])也被添加到了 currentLevel,使得 currentLevel 变成 [3, 9, 20, 15, 7]
  • 最终,result 中的所有子列表都指向同一个 currentLevel,导致 result 中的每一层显示的都是完整的 [3, 9, 20, 15, 7],而不是分层的结果。

正确的做法:

要避免这个问题,需要在每次开始遍历新的一层时,创建一个新的 currentLevel 列表。这样,每一层的节点值都会存储在独立的列表中。具体修改如下:

java 复制代码
public class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) {
            return result;
        }

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

        while (!queue.isEmpty()) {
            int levelSize = queue.size();
            // 在每一层遍历开始时,重新初始化 currentLevel
            List<Integer> currentLevel = new ArrayList<>();

            for (int i = 0; i < levelSize; i++) {
                TreeNode currentNode = queue.poll();
                currentLevel.add(currentNode.val);

                if (currentNode.left != null) {
                    queue.offer(currentNode.left);
                }
                if (currentNode.right != null) {
                    queue.offer(currentNode.right);
                }
            }
            result.add(currentLevel); // 添加当前层的节点值到结果中
        }

        return result;
    }
}

解释修改后的代码:

  1. List<Integer> currentLevel = new ArrayList<>(); 放在 while 循环内部

    • 每次进入 while 循环(即开始遍历新的层级节点)时,都会创建一个新的 currentLevel 列表,用来存储该层的节点值。
    • 这样可以保证每一层的节点值都保存在独立的列表中,不会影响其他层的结果。
  2. result.add(currentLevel); 正确地添加当前层的结果

    • 每一层遍历完成后,将当前层的节点值列表 currentLevel 添加到 result 中。
    • 由于每次都是一个新的 currentLevel,因此不会有多个层共享同一个列表引用,最终的 result 会包含每一层的正确结果。

结论:

这个问题的核心是你需要为每一层创建一个新的 currentLevel,而不是在所有层之间共享一个 currentLevel。在每次开始遍历新的一层时,初始化一个新的 currentLevel,可以保证每一层的节点值都被正确地存储和输出。

相关推荐
ALISHENGYA6 分钟前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(实战训练三)
数据结构·c++·算法·图论
柒月的猫2 小时前
翻转(蓝桥杯2023大学C组试题E)
职场和发展·蓝桥杯
Dream it possible!2 小时前
LeetCode 热题 100_LRU 缓存(35_146_中等_C++)(哈希表 + 双向链表)(构造函数声明+初始化列表=进行变量初始化和赋值)
c++·leetcode·缓存
我码玄黄2 小时前
正则表达式优化之算法和效率优化
前端·javascript·算法·正则表达式
Solitudefire3 小时前
蓝桥杯刷题——day9
算法·蓝桥杯
三万棵雪松4 小时前
1.系统学习-线性回归
算法·机器学习·回归·线性回归·监督学习
Easy数模4 小时前
基于LR/GNB/SVM/KNN/DT算法的鸢尾花分类和K-Means算法的聚类分析
算法·机器学习·支持向量机·分类·聚类
2401_858286114 小时前
117.【C语言】数据结构之排序(选择排序)
c语言·开发语言·数据结构·笔记·算法·排序算法
thesky1234564 小时前
活着就好20241226
学习·算法
td爆米花5 小时前
C#冒泡排序
数据结构·算法·排序算法