字节微软阿里——513. 找树左下角的值

35 阅读4分钟

513. 找树左下角的值

给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。

假设二叉树中至少有一个节点。

示例 1:

tree1-1720158905794-3.jpg

输入: root = [2,1,3]
输出: 1

示例 2:

tree2-1720158905794-5.jpg

输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7 

提示:

  • 二叉树的节点个数的范围是 [1,104]
  • -2^31 <= Node.val <= 2^31 - 1

回溯深度,前中后序都行。无返回值。

class Solution {
    // 记录二叉树的最大深度
    int maxDepth = 0;
    // 记录 traverse 递归遍历到的深度
    int depth = 0;
    TreeNode res = null;

    public int findBottomLeftValue(TreeNode root) {
        traverse(root);
        return res.val;
    }

    void traverse(TreeNode root) {
        if (root == null) {
            return;
        }
        
        // 前序遍历位置
        depth++;
        
        // 下面三块代码的顺序无所谓。如果找到更大的深度,则更新数据
        if (depth > maxDepth) {
            // 到最大深度时第一次遇到的节点就是左下角的节点
            maxDepth = depth;
            res = root;
        }
        traverse(root.left);
        traverse(root.right);
        
        // 后序遍历位置
        depth--;
    }
}
  • 时间复杂度O(n)
  • 空间复杂度O(h),h是二叉树的高度。

有返回值的DFS,把回溯中的height变成递归参数

class Solution {
    private int curVal = 0; // 当前找到的最左下角节点的值
    private int curHeight = -1; // 当前找到的最左下角节点的高度,这里一定要是-1,不能是0,因为dfs的height参数初始值为0.

    /**
     * 查找二叉树中最左下角节点的值
     *
     * @param root 二叉树的根节点
     * @return 最左下角节点的值
     */
    public int findBottomLeftValue(TreeNode root) {
        dfs(root, 0); // 开始深度优先搜索,初始高度为0
        return curVal; // 返回最左下角节点的值
    }

    /**
     * 深度优先搜索方法,用于查找最左下角的节点
     *
     * @param node 当前节点
     * @param height 当前节点的高度
     */
    private void dfs(TreeNode node, int height) {
        if (node == null) {
            return; // 如果当前节点为空,返回
        }

        // 重点:如果当前节点是新的最左下角节点,即第一次遇到更大的深度,则更新 curHeight 和 curVal
        // 这段代码放在前序、中序、后序都可以。
        if (height > curHeight) {
            curHeight = height;
            curVal = node.val;
        }

        // 先递归左子树,再递归右子树,确保优先访问左子节点
        dfs(node.left, height + 1);
        dfs(node.right, height + 1);
    }
}
  • 时间复杂度:O(n),其中 n 是二叉树的节点数目。需要遍历 n 个节点。
  • 空间复杂度:O(n)。递归栈需要占用 O(n) 的空间。

BFS

class Solution {
    /**
     * 查找二叉树中最左下角节点的值
     *
     * @param root 二叉树的根节点
     * @return 最左下角节点的值
     */
    public int findBottomLeftValue(TreeNode root) {
        int ret = 0; // 初始化返回值,表示最左下角节点的值
        Queue<TreeNode> queue = new ArrayDeque<>(); // 创建一个队列用于层次遍历(广度优先搜索)
        queue.offer(root); // 将根节点添加到队列中

        // 当队列不为空时,继续遍历
        while (!queue.isEmpty()) {
            TreeNode p = queue.poll(); // 从队列中取出当前节点

            // 先检查右子节点并加入队列,因为要找的是最左下角的节点,
            // BFS的过程中,最后一个遍历到的节点一定是当前层最左边的节点
            if (p.right != null) {
                queue.offer(p.right); // 将右子节点添加到队列中
            }
            // 再检查左子节点并加入队列
            if (p.left != null) {
                queue.offer(p.left); // 将左子节点添加到队列中
            }

            // 更新当前节点的值为最新的节点值,因为我们是从右往左遍历,
            // 最终队列为空时,ret值就是最左下角节点的值。这行代码也可以放在两个if的上面。
            ret = p.val;
        }

        return ret; // 返回最左下角节点的值
    }
}
  • 时间复杂度:O(n),其中 n 是二叉树的节点数目。
  • 空间复杂度:O(n)。如果二叉树是满完全二叉树,那么队列 q 最多保存 ⌈n/2⌉ 个节点。

层序遍历

class Solution {
    public int findBottomLeftValue(TreeNode root) {
        // 层次(从左到右)遍历,记录每行的第一个元素
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        
        Integer ans = null;
        while (!queue.isEmpty()) {
            ans = null;
        
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                // 记录队首节点
                TreeNode node = queue.poll();
                // 刚开始for循环时ans为空,所以把node赋给它。本轮for循环的剩余循环中ans就不为空了。即ans每次都会被赋为每一层的第一个节点。
                if (ans == null) ans = node.val;
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            }
        }

        return ans;
    }
}
  • 时间复杂度:O(n),其中 n 是二叉树的节点数目。
  • 空间复杂度:O(n)。如果二叉树是满完全二叉树,那么队列 q 最多保存 ⌈n/2⌉ 个节点。