LeetCode Maximum Width of Binary Tree

来源:互联网 发布:linux 定时器 编辑:程序博客网 时间:2024/05/16 09:18

Given a binary tree, write a function to get the maximum width of the given tree. The width of a tree is the maximum width among all levels. The binary tree has the same structure as a full binary tree, but some nodes are null.

The width of one level is defined as the length between the end-nodes (the leftmost and right most non-null nodes in the level, where the null nodes between the end-nodes are also counted into the length calculation.

Example 1:

Input:            1         /   \        3     2       / \     \        5   3     9 Output: 4Explanation: The maximum width existing in the third level with the length 4 (5,3,null,9).

Example 2:

Input:           1         /          3           / \             5   3     Output: 2Explanation: The maximum width existing in the third level with the length 2 (5,3).

Example 3:

Input:           1         / \        3   2        /              5      Output: 2Explanation: The maximum width existing in the second level with the length 2 (3,2).

Example 4:

Input:           1         / \        3   2       /     \        5       9      /         \    6           7Output: 8Explanation:The maximum width existing in the fourth level with the length 8 (6,null,null,null,null,null,null,7).

Note: Answer will in the range of 32-bit signed integer.

题解:

给定一棵二叉树,求这棵二叉树的最大宽度。此宽度定义为每一层中最右边的节点位置数-最左边的节点位置数,注意,这里的位置数是针对完全二叉树而言的,在完全二叉树中,需要将不存在的空节点的位置也考虑在内,用来标记相应的那一层的所有节点。我一开始的方法比较繁琐,是将所有空节点也保存在一个arraylist中,而这个arraylist在每一层中都有,然后遍历完一层,采用从首尾开始寻找第一个非空节点,然后用最后一个位置的节点位置-第一个开始位置非空节点的位置,此差值即为那一层的最大宽度。但是这样做出现了超时现象。我原来的代码如下所示,这个代码会出现超时错误。

class Solution {    public int widthOfBinaryTree(TreeNode root)    {        if(root == null)            return 0;        int height = getDepth(root);        Queue<TreeNode> queue = new LinkedList<>();        queue.add(root);        int max = 1;        for(int i = 0; i < height - 1; i++)        {            ArrayList<String> list = new ArrayList<>();            int curr = 0;            int length = queue.size();            while(length-- > 0)            {                TreeNode node = queue.poll();                if(node == null)                {                    queue.add(null);                    queue.add(null);                    list.add(" ");                    list.add(" ");                }                else if(node != null)                {                    if(node.left != null)                    {                        queue.add(node.left);                        list.add(String.valueOf(node.left.val));                    }                    else if(node.left == null)                    {                        queue.add(null);                        list.add(" ");                    }                    if(node.right != null)                    {                        queue.add(node.right);                        list.add(String.valueOf(node.right.val));                    }                    else if(node.right == null)                    {                        queue.add(null);                        list.add(" ");                    }                }            }            int start = 0;            int end = list.size() - 1;            while(start < end)            {                if(list.get(start) == " ")                {                    start = start + 1;                }                if(list.get(end) == " ")                {                    end = end - 1;                }                if(list.get(start) != " " && list.get(end) != " ")                    break;            }            curr = end - start + 1;            max = max > curr ? max : curr;        }        return max;    }    public int getDepth(TreeNode root)    {        if(root == null)            return 0;        int left = getDepth(root.left);        int right = getDepth(root.right);        return 1 + Math.max(left,right);    }}

上述代码不可行,那么经过byr人的指导,想到了另一种方法,只需要按照完全二叉树节点的计数方法保存每个节点在整棵二叉树中的位置下标,一般当前位置是i,则其左孩子节点的下标为2*i,其右孩子下标为2*i+1。所以最后只需要将每一层中最大的孩子的下标数-开始的最小孩子的下标数,就是最大宽度,采用层次遍历的方法来执行即可。

public class Solution {    public int widthOfBinaryTree(TreeNode root)    {     if(root == null)       return 0;     Queue<TreeNode> queue = new LinkedList<>();   //保存当前层的树节点     Queue<Integer> queuePos = new LinkedList<>(); //保存上面队列中树节点对应的位置标号     queue.add(root);         queuePos.add(1);      //在顶层根节点位置为1     int countCurrent = 1;   //记录当前正在遍历层的剩余数量     int countTmp = 0;      //记录下一层的节点数量     int max = countCurrent;     int start = 1;     int end = 1;            //每一层中最大孩子的位置下标     while(!queue.isEmpty())   //首先判断此队列是否为空     {         TreeNode current = queue.poll();         end = queuePos.poll();         if(current.left != null)         {             queue.add(current.left);             queuePos.add(2*end);     //左孩子的下标             countTmp++;         }         if(current.right != null)         {             queue.add(current.right);              queuePos.add(2*end+1);  //右孩子的下标             countTmp++;               }                        if(--countCurrent == 0)    //判断是否将当前这一层的所有节点都遍历完         {             max = max > (end - start + 1) ? max : (end - start + 1);   //start要么为1,要么就为下一层中开头的那个节点的下标             countCurrent = countTmp;   //这里将新的下一层的节点个数赋给这个变量             countTmp = 0;              //将下一层的节点计数赋值为0             start = queuePos.isEmpty() ? 1 : queuePos.peek();      //此start值为下一层开头的第一个节点的下标         }     }     return max;}

通过这道题,也可以看到我虽然对于写二叉树的层次遍历非常熟悉,但是对于层次遍历中间的一些其他技巧掌握地还不是特别熟悉,并且对于一棵非完全二叉树采用完全二叉树的节点计数方法来设置每个节点的值,不是特别熟悉,所以这里有待加强。尤其是针对完全二叉树的节点计数方法,每一个左孩子为其父亲节点下标的两倍,其右孩子节点的下标为其父亲下标的两倍+1,这个规律还可以应用到非完全二叉树的按照完全二叉树计数的方式中,非常好用。对于层次遍历,内存循环也不一定要用while,可以用if来做,也可以用for循环来实现,非常灵活。