LeetCode662 Maximum Width of Binary Tree

example will help us to understand this problem straight forwardly.

Input:

       1
     /   \
    3     2
   / \     \  
  5   3     9 

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

Input:

      1
     / \
    3   2
   /     \  
  5       9 
 /         \
6           7

Output: 8
Explanation:The maximum width existing in the fourth level with the length 8 (6,null,null,null,null,null,null,7).

idea:
starting from the root, and we do a level order tranverse. we will set root as 0, if move left, then minus 1, if move right, we plus 1.
and the width = the last item that put into this level - the first item put into this level. for whole level, we need to maintain a global maximum.
so based on this idea, I came up with a solution that turns out to be wrong.

class Solution {
    public int widthOfBinaryTree(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        TreeNode leftP = root;
        TreeNode rightP = root;
        int leftIndex = 0;
        int rightIndex = 0;
        int width = 1;
        while (leftP != null && rightP != null) {
            
            if (leftP.left != null) {
                leftP = leftP.left;
                leftIndex = leftIndex - 1;
            } else if (leftP.right != null) {
                leftP = leftP.right;
                leftIndex = leftIndex + 1;
            } else {
                leftP = null;
            }
            
            if (rightP.right != null) {
                rightP = rightP.right;
                rightIndex = rightIndex + 1;
            } else if (rightP.left != null) {
                rightP = rightP.left;
                rightIndex = rightIndex - 1;
            } else {
                rightP = null;
            }
            int tempWidth = rightIndex - leftIndex + 1;
            width = Math.max(width, tempWidth);
        }
        return width;
    }
}

and clearly, this solution failed the following case:
Input:

      1
     /  
    3    
   / \       
  5   3     

so on second thought, what we need to do is to get the leftmost and the rightmost nodeIndex, so it’s kind of like the left project and the right project of a tree.
so the previous solution is modified to:

class Solution {
    public int widthOfBinaryTree(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        TreeNode leftP = root;
        TreeNode rightP = root;
        int leftIndex = 0;
        int rightIndex = 0;
        int width = 1;
        while (leftP != null && rightP != null) {
            
            
            if (leftP.left != null) {
                leftP = leftP.left;
                leftIndex = leftIndex - 1;
            } else if (leftP.right != null) {
                leftP = leftP.right;
                leftIndex = leftIndex + 1;
            } else {
                break;
            }
            
            if (rightP.right != null) {
                rightP = rightP.right;
                rightIndex = rightIndex + 1;
            } else if (rightP.left != null) {
                rightP = rightP.left;
                rightIndex = rightIndex - 1;
            } else {
                break;
            }
            int tempWidth = rightIndex - leftIndex;
            width = Math.max(width, tempWidth);
        }
        return width;
    }
}

but the result is still not right.

the reason for this, is I use the wrong formula to calculate width of each level:
#int tempWidth = rightIndex - leftIndex; this is not right, just use the case of:
[1,1,1,1,null,null,1,1,null,null,1]

solutions provide by Leetcode:
01: using BFS
my original thought of this problem using level order is right, but I’m not thinking that straight. clearly, when I’m using queue, I know how to get the first and the last node of current level, but I don’t know how to calculate the width of each level since the size of current level is not the width.
so from here, I quit thinking and seek for other possible solutions.
but, what if for each level, we use null nodes to fill the whole level. and pull the queue’s head and tail until we reached the non-null nodes. then the size of this queue is the width of this level.
the only tricky thing is, choose a suitable data structure so we can poll the First and last element efficiently.
and the answer is obviously: deque.

so the code will be as following:

class Solution {
    public int widthOfBinaryTree(TreeNode root) {
        if (root == null) {
            return 0;
        }
        
        Deque<TreeNode> deque = new LinkedList<>();
        deque.offer(root);
        int width = 0; //global max width 
        
        while (!deque.isEmpty()) {
            int size = deque.size();
            width = Math.max(width, size);
            
            for (int i = 0; i < size; i++) {
                TreeNode cur = deque.poll();
                if (cur == null) {
                    deque.offer(null);
                    deque.offer(null);
                } else { 
                    if (cur.left != null) {
                        deque.offer(cur.left);
                    } else {
                        deque.offer(null);
                    }
                    if (cur.right != null) {
                        deque.offer(cur.right);
                    } else {
                        deque.offer(null);
                    }
                }
            }
            
            while (deque.size() != 0 && deque.peekFirst() == null) { //elimiate all the null nodes starting from left
                deque.pollFirst();
            }
            while (deque.size() != 0 && deque.peekLast() == null) { //eliminate all the null nodes starting from right
                deque.pollLast();
            }
        }
        return width;
    }
}

you may have a little concern about the out while loop make never ends. well, it actually can, because if this level is full of null nodes, then in inner loop, deque will be eliminate to nothing, that’s when the while loop ends.

however, this BFS solution is TLE.

so I looked for dfs solution:

class Solution {
    public int widthOfBinaryTree(TreeNode root) {
        if (root == null) {
            return 0;
        }
        List<Integer> start = new ArrayList<>();
        List<Integer> end = new ArrayList<>();
        return dfs(root, 0, 1, start, end); //dfs will return the max width of this root tree
    }
    
    private int dfs(TreeNode root, int level, int order, List<Integer> start, List<Integer> end) {
        if (root == null) return 0;
        if (start.size() == level) { //don;t understand why, if the size of start is the same as level, means we are moving to next level? so start need to mark this point as starting point of next level
            start.add(order);
            end.add(order);
        } else {
            end.set(level, order); //end will keep update the last element's index
        }
        int width = end.get(level) - start.get(level) + 1;
        int left = dfs(root.left, level + 1, 2 * order, start, end);
        int right = dfs(root.right, level + 1, 2 * order + 1, start, end);
        return Math.max(width, Math.max(left, right));
    }
}

not fully understand this solution, but will come back later.

posted @ 2020-08-10 03:08  EvanMeetTheWorld  阅读(17)  评论(0)    收藏  举报