计算二叉树的最大宽度,宽度是指每层的最右边到最左边节点的距离。
从最左边的非null节点到最右边的非null节点(包含它们中间的null节点)。
思路:
1.BFS
与以往不同的是,这里不仅仅是统计一层的节点个数,还要算上节点中间的null(左右边界外的null不算)。
把null节点也转入queue会浪费空间,还要和边界外的null区分,比较麻烦,
因为是二叉树,所以给每个节点一个id, 左节点的id = root id * 2, 右节点id = root id * 2+ 1.
id可以就这么顺序排下去,如果担心id过大会溢出,
可以让每一层的id都从0开始(cur_id = id-left)。
public int widthOfBinaryTree(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
int maxWidth = 0;
//用node.val保存id,这会修改掉节点值,题里不影响,实际情况要斟酌
root.val = 0;
queue.add(root);
while(!queue.isEmpty()) {
int size = queue.size();
int left = queue.peek().val; //最左边节点的id
int right = left;
for(int i = 0; i < size; i++) {
TreeNode cur = queue.poll();
if(cur.left != null) {
//担心id过大,让每一层id都从0开始,其实不减left也可以,并不会超过int最大值
cur.left.val = (cur.val-left) * 2;
queue.add(cur.left);
}
if(cur.right != null) {
//担心id过大,让每一层id都从0开始,其实不减left也可以,并不会超过int最大值
cur.right.val = (cur.val-left) * 2 + 1;
queue.add(cur.right);
}
if(i == size - 1) right = cur.val;
}
maxWidth = Math.max(maxWidth, right-left+1);
}
return maxWidth;
}
2.DFS
用DFS递归求每个节点的左右子树最大宽度,最大宽度是在 当前层的当前node到最左边node的距离,左子树的最大宽度,右子树的最大宽度,三者中取最大。
其中左子树宽度,右子树宽度也是递归,在 当前层的当前node到最左边node的距离,左子树的最大宽度,右子树的最大宽度,三者中取最大。
直到到达null节点,宽度返回0。
至于如何计算距离,可给每个node一个id,左子树的id就是root id✖️2,右子树id是root id✖️2+1,距离就是当前id减最左边id再加1
而如何判断最左边的id,可用一个list保存每层最左边的id。每层的第一个节点,也就是层数==list的size时加入节点id
public int widthOfBinaryTree(TreeNode root) {
List<Integer> ids = new ArrayList<>();
return dfs(root, ids, 0, 0);
}
int dfs(TreeNode root, List<Integer> ids, int depth, int id) {
if(root == null) return 0;
if(depth == ids.size()) ids.add(id);
return Math.max(id - ids.get(depth) + 1, //当前层width
Math.max(dfs(root.left, ids, depth+1, (id-ids.get(depth))*2), //左子树width
dfs(root.right, ids, depth+1, (id-ids.get(depth))*2+1)));
}