LeetCode 662. 二叉树最大宽度

截止到目前我已经写了 500多道算法题,其中部分已经整理成了pdf文档,目前总共有1000多页(并且还会不断的增加),大家可以免费下载
下载链接:https://pan.baidu.com/s/1hjwK0ZeRxYGB8lIkbKuQgQ
提取码:6666

LeetCode 662. 二叉树最大宽度_第1张图片
LeetCode 662. 二叉树最大宽度_第2张图片
LeetCode 662. 二叉树最大宽度_第3张图片
每一行从最左边到最右边我们很容易想到的就是二叉树的BFS遍历,他就是一层一层遍历的,关于二叉树的BFS不明白的可以看下下面的视频。

LeetCode 662. 二叉树最大宽度_第4张图片

视频链接

所以这题思路很容易想到,就是遍历每一层的时候计算这一层最左边节点到最右边节点的距离,大致代码如下

public int widthOfBinaryTree(TreeNode root) {
    if (root == null)
        return 0;
    //使用双端队列
    Deque<TreeNode> queue = new LinkedList<>();
    //把根节点加入到队列中
    queue.offer(root);
    //记录最大的宽度
    int maxWide = 0;
    while (!queue.isEmpty()) {
        //当前层节点的数量
        int levelCount = queue.size();
        // int gap = 当前层最左边到最右边的距离
        maxWide = Math.max(maxWide, gap);
        //遍历当前层的所有节点,把他们的子节点在加入到队列中
        for (int i = 0; i < levelCount; i++) {
            TreeNode node = queue.poll();
            //如果左子节点不为空,就把左子节点加入到队列中
            if (node.left != null) {
                queue.offer(node.left);
            }
            //如果右子节点不为空,就把右子节点加入到队列中
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
    }
    return maxWide;
}

他就是从上往下一层一层遍历的,遍历每一层的时候我们需要计算当前层的最大距离,保留最大的即可。这里关键是怎么计算当前层的最大距离。

我们可以这样来计算,把它想象成为一颗满二叉树,假如根节点是遍历的第1个节点,那么他的两个子节点分别是遍历的第2个和第3个节点。并且可以推算出如果一个节点是第n个遍历的,那么他的两个子节点分别是第n*2和n*2+1个遍历的,具体我们来画个图看一下

LeetCode 662. 二叉树最大宽度_第5张图片

我们可以把这些值存到一个map中,也可以把它直接存到节点中,这里我们就把他存到节点中,在遍历每一层的时候用当前层最右边的值减去最左边的值+1就是当前层的最大距离,来看下最终代码。

public int widthOfBinaryTree(TreeNode root) {
    if (root == null)
        return 0;
    //使用双端队列
    Deque<TreeNode> queue = new LinkedList<>();
    //把根节点加入到队列中
    queue.offer(root);
    //根节点的值我们把它修改为1
    root.val = 1;
    //记录最大的宽度
    int maxWide = 0;
    while (!queue.isEmpty()) {
        //当前层节点的数量
        int levelCount = queue.size();
        //当前层最左边节点的值
        int left = queue.peekFirst().val;
        //当前层最右边节点的值
        int right = queue.peekLast().val;
        //当前层的最大宽度就是right - left + 1,
        //这里计算之后要保留最大的
        maxWide = Math.max(maxWide, right - left + 1);
        //遍历当前层的所有节点,把他们的子节点在加入到队列中
        for (int i = 0; i < levelCount; i++) {
            TreeNode node = queue.poll();
            int position = node.val;
            //如果左子节点不为空,就把左子节点加入到队列中
            if (node.left != null) {
                node.left.val = position * 2;
                queue.offer(node.left);
            }
            //如果右子节点不为空,就把右子节点加入到队列中
            if (node.right != null) {
                node.right.val = position * 2 + 1;
                queue.offer(node.right);
            }
        }
    }
    return maxWide;
}

这里因为左边节点先入队,所以peekFirst()返回的就是当前层最左边的节点,右边节点是最后入队的,所以peekLast()返回的是当前层最右边的节点。

LeetCode 662. 二叉树最大宽度_第6张图片

//记录最大的宽度
int maxWide = 0;

public int widthOfBinaryTree(TreeNode root) {
    dfs(root, 0, 1, new ArrayList<>(), new ArrayList<>());
    return maxWide;
}

/**
 * @param root
 * @param level    遍历到第几层
 * @param position 每个节点在满二叉树中的位置
 * @param left     只记录最左边的节点,每层只记录一个
 * @param right    只记录遍历过的最右边节点,每层只记录一个(这里是遍历过的,如果当前层有更右边的节点,
 *                 会把当前层的替换)
 */
public void dfs(TreeNode root, int level, int position, List<Integer> left, List<Integer> right) {
    if (root == null)
        return;
    //首次到当前层,要把当前值分别加入到left和right中
    if (left.size() == level) {
        left.add(position);
        right.add(position);
    } else {//如果当前层已经遍历过,会替换掉
        right.set(level, position);
    }
    //递归遍历下一层的左右子节点
    dfs(root.left, level + 1, position << 1, left, right);
    dfs(root.right, level + 1, position * 2 + 1, left, right);
    //计算当前层的最大间距,保留最大值
    maxWide = Math.max(maxWide, right.get(level) - left.get(level) + 1);
}

你可能感兴趣的:(数据结构和算法,LeetCode,662,二叉树,最大宽度,算法)