LeetCode 662. 二叉树的最大宽度

二叉树在每一层的宽度,定义为这一层中,最左侧节点到最右侧节点之间的长度(中间的null节点也被计算在内)。二叉树的最大宽度,就是每一层的宽度中的最大值。

根据题目描述来看,最直观的想法就是BFS层序遍历。遍历每一层,求每一层的宽度,然后取一个max。关键是每一层的宽度怎么求?由于中间允许有null节点。想了一会儿后,发现用数组模拟二叉树时,节点在数组中都有一个下标,这个下标,可以用来解这道题。

在用数组模拟二叉树时,每个节点在数组中会有一个下标(编号)。当是满二叉树时,我们会按照层序遍历的顺序,依次给节点编号。
若根节点编号从1开始,则对于编号为x的节点,其左儿子的编号为2 * x,其右儿子的编号为2 * x + 1
(根节点编号从1开始,计算比较方便;若根节点编号从0开始,则左儿子为2 * x + 1,右儿子为2 * x + 2)。

那么,将题目中这棵树看成满二叉树(为空的节点也认为是有节点),我们对每个节点进行编号。求某一层的宽度,只需要用该层最后一个节点的编号,减去该层第一个节点的编号,即可算出中间的长度。

对节点增加一个编号,可以通过创建一个新的数据结构来做,也可以用Map来保存每个节点对应的编号,也可以用Queue来对编号进行存储(因为每一次都是处理一层的节点),下面选择用Queue来存储节点编号

代码如下

class Solution {
    public int widthOfBinaryTree(TreeNode root) {
        if (root == null) return 0;
        // 需要计算每一层的宽度, 并从中取最大值, 用BFS来做
        Queue<TreeNode> queue = new LinkedList<>();
        Queue<Integer> indexQueue = new LinkedList<>();
        int ans = 1;
        queue.offer(root);
        indexQueue.offer(1);
        while (!queue.isEmpty()) {
            // 将这一层的拿出来
            int size = queue.size();
            int left = 0; // 该层第一个节点的下标
            int right = 0; // 该层最后一个节点的下标
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                int index = indexQueue.poll();
                if (node.left != null) {
                    queue.offer(node.left);
                    indexQueue.offer(2 * index);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                    indexQueue.offer(2 * index + 1);
                }
                if (i == 0) left = index;
                if (i == size - 1) right = index;
            }
            ans = Math.max(ans, right - left + 1);
        }
        return ans;
    }
}

这道题也可以用DFS来做,不过DFS的思路没有BFS直观。
用DFS来做,我们采用前序遍历,因为用前序遍历时,每一层中的最左侧的节点,是这一层所有节点中,第一个被访问到的。而我们需要每一层的第一个节点,这样的信息。只要获取到每一层最左侧节点的下标。
在后续的遍历中,当访问到某一个节点时,只需要用该节点的下标,减去当前层的最左侧节点的下标,得到一个长度,用这个长度去更新答案即可,因为会遍历所有的节点,那么这个答案总是会被当前层更大的宽度所更新,最后得到的就是所有层中的最大宽度。

我们需要一个Map,来记录每一层最左侧节点的下标

class Solution {

    int ans = 0;
    Map<Integer, Integer> leftIndex = new HashMap<>();
    public int widthOfBinaryTree(TreeNode root) {
        dfs(root, 0, 1);
        return ans;
    }

    // 访问节点node, 该节点所在的层为 depth, 其下标为 pos
    public void dfs(TreeNode node, int depth, int pos) {
        if (node == null) return;
        // 采用前序遍历, 则每一层的最左侧节点, 一定是最先被访问到的
        // 第一次被访问到的话, 则记录该层最左侧节点下标的信息
        if (!leftIndex.containsKey(depth)) leftIndex.put(depth, pos);
        ans = Math.max(ans, pos - leftIndex.get(depth) + 1);
        dfs(node.left, depth + 1, 2 * pos);
        dfs(node.right, depth + 1, 2 * pos + 1);
    }
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值