第662题 二叉树最大宽度(暴力存储+深度优先+广度优先)

题目描述:

给你一棵二叉树的根节点 root ,返回树的 最大宽度 。

树的 最大宽度 是所有层中最大的 宽度 。

每一层的 宽度 被定义为该层最左和最右的非空节点(即,两个端点)之间的长度。将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 null 节点,这些 null 节点也计入长度。

题目数据保证答案将会在  32 位 带符号整数范围内。

LevelAC rate
Medium43.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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值