662. 二叉树最大宽度
思路:
最开始我的想法是直接BFS,然后记录每一层从左到右的节点,遍历完一层后去掉左右的空节点,中间的节点数就是宽度了,然后就有:
public int widthOfBinaryTree(TreeNode root) {
if(root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
int max = 0;
while(!queue.isEmpty()){
int size = queue.size();
List<TreeNode> list = new ArrayList<>();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
list.add(node);
if(node == null){
queue.add(null);
queue.add(null);
}else{
queue.add(node.left);
queue.add(node.right);
}
}
int i=0;
int j=size-1;
while(i<size && list.get(i) == null){
i++;
}
while(j>=0 && list.get(j) == null){
j--;
}
if(j>=i){
max = Math.max(max,j-i+1);
}else{
break;
}
}
return max;
}
方法貌似是对了,但是超时了😭,可能因为while循环中还嵌套两个while吧,因为要算个数。如果要减少时间复杂度,比较可行的就是去点内层循环,如何去掉呢?如果我们计算的不是个数,而是计算每层的最左节点和最右节点的位置之差,那就不需要再遍历一遍了!我们用一个链表来记录每个节点的位置。
不过这里还要用到一个性质,任意节点index的左子节点和右子节点分别为2index,2index+1,还是右BFS有:
private int maxW = 1;
public int widthOfBinaryTree(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> queue = new LinkedList<>();
LinkedList<Integer> indexList = new LinkedList<>();
queue.add(root);
indexList.add(1);
while (!queue.isEmpty()) {
int size = queue.size();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
int index = indexList.removeFirst();
if (node.left != null) {
queue.add(node.left);
indexList.add(2 * index);
}
if (node.right != null) {
queue.add(node.right);
indexList.add(2 * index + 1);
}
}
if (indexList.size() >= 2) {
maxW = Math.max(maxW, indexList.getLast() - indexList.getFirst() + 1);
}
}
return maxW;
}
同样的,按照这个思路也可以采用DFS:
private int maxW = 0;
public int widthOfBinaryTree(TreeNode root) {
dfs(root, 1, 1, new ArrayList<>());
return maxW;
}
private void dfs(TreeNode r, int level, int index, List<Integer> left) {
if(r == null) return;
if(level > left.size()) left.add(index);//新一层第一个节点
maxW = Math.max(maxW, index - left.get(level-1) + 1);//与当前层第一个节点宽度差,level-1是因为索引从0开始
dfs(r.left, level+1, index*2, left);
dfs(r.right, level+1, index*2+1, left);
}