题目描述:
给你一棵二叉树的根节点 root ,返回树的 最大宽度 。
树的 最大宽度 是所有层中最大的 宽度 。
每一层的 宽度 被定义为该层最左和最右的非空节点(即,两个端点)之间的长度。将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 null 节点,这些 null 节点也计入长度。
题目数据保证答案将会在 32 位 带符号整数范围内。
Level | AC rate |
Medium | 43.6% |
题目解析:
一眼看到这道题,我就想到了第655题。链接如下:
第655题 输出二叉树输出二叉树,两次遍历https://mp.weixin.qq.com/s?__biz=Mzk0MjM5ODM2NQ==&mid=2247483732&idx=1&sn=d09bb327c7b9c935b4c6a65d07b3f3f6&chksm=c2c28fa6f5b506b04dd242954ba6199591b253e165a4680479ccd47950403840cd0440c733bb&scene=21#wechat_redirect我先通过一次深度遍历,找到二叉树的深度,根据深度构造二维矩阵,然后再通过一次遍历将各个节点对应的位置填进去。按行遍历二维矩阵,将每行起始两个有效数字索引之差加1作为每层的宽度。然后进行取最大值输出即可:
// 矩阵构造
class Solution {
int[][] arr;
int depth;
public int widthOfBinaryTree(TreeNode root) {
int ans = 0;
dfs(root,1);
int col = (int)Math.pow(2,depth-1);
arr = new int[depth+1][col];
fill(root,1,1);
for(int i = 1; i<arr.length; i++){
int flag = 0;
int med = 0;
for(int j = 0; j<arr[0].length; j++){
if(arr[i][j]!=0&&flag==0){
med = j;
flag = 1;
}
ans = Math.max(arr[i][j]-arr[i][med]+1,ans);
}
}
return ans;
}
void dfs(TreeNode root, int H){
if(root==null)return;
depth = Math.max(depth,H);
dfs(root.left,H+1);
dfs(root.right,H+1);
}
void fill(TreeNode root, int H , int index){
if(root==null)return;
int fun = (int)Math.pow(2,H-1);
arr[H][index-fun] = index;
fill(root.left,H+1,2*index);
fill(root.right,H+1,2*index+1);
}
}
但这遇到了超出内存限制的问题。
深度遍历:
考虑到我们使用矩阵进行每个值编号存储会造成内存不够的情况,所以我们使用哈希表来进行存储,因为我们使用的遍历方式是前序遍历,所以每一层中的所有元素一定是最左边那个元素最先遍历到,我们通过哈希表来进行判断,若没有计算到过这一层,我们把该点对应的深度和序号放进哈希表中,如果有的话,我们根据序号插值来对ans取最大值即可,代码如下:
// 深度优先
class Solution {
Map<Integer, Integer> map = new HashMap<>();
int ans;
public int widthOfBinaryTree(TreeNode root) {
ans = 0;
dfs(root,0,1);
return ans;
}
void dfs(TreeNode root, int H, int index){
if(root==null){
return;
}
if(!map.containsKey(H))map.put(H,index);
ans = Math.max(index-map.get(H)+1,ans);
dfs(root.left,H+1,2*index);
dfs(root.right,H+1,2*index+1);
}
}
执行用时:1 ms, 在所有 Java 提交中击败了99.79%的用户
内存消耗:40.7 MB, 在所有 Java 提交中击败了95.07%的用户
广度遍历:
根据层序遍历的原理,将各个节点对应的深度和序号存进二维链表,依次遍历,将每个链表元素中的最后一个序号减去第一个序号加1即为该层的宽度,代码如下:
// 广度优先
class Solution {
List<List<Integer>> list = new ArrayList<List<Integer>>();
public int widthOfBinaryTree(TreeNode root) {
int ans = 0;
GDYX(root,0,1);
for(int i = 0; i<list.size(); i++){
int len = list.get(i).size();
ans = Math.max(list.get(i).get(len-1)-list.get(i).get(0)+1,ans);
}
return ans;
}
void GDYX(TreeNode root, int H, int index){
if(root==null) return;
List<Integer> temp;
if(H>=list.size())temp = new ArrayList<Integer>();
else temp = list.get(H);
temp.add(index);
if(H>=list.size())list.add(temp);
else list.set(H,temp);
GDYX(root.left,H+1,index*2);
GDYX(root.right,H+1,index*2+1);
}
}
执行用时:2 ms, 在所有 Java 提交中击败了27.34%的用户
内存消耗:40.8 MB, 在所有 Java 提交中击败了87.84%的用户
学习总结:
考点其实就考了一个二叉树的序号问题,一个结点的序号为i,那么其左结点的序号为2*i,其右结点的序号为2*i+1。