求一颗二叉树的宽度

316 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情

前言

如何完成二叉树的宽度优先遍历(常见题目:求一颗二叉树的宽度)

二叉树的宽度优先遍历

以下面的二叉树为例:

flowchart TB
    A(1) --> B(2) & C(3)
    B(2) --> D(4) & E(5)
    C(3) --> F(6) & G(7)

如果对其进行宽度优先遍历,打印出来的顺序是1,2,3,4,5,6,7

Java版

public static void w(Node head){
    if(head == null){
        return;
    }
    Queue<Node> queue = new LinkedList<>();
    queue.add(head);
    while(!queue.isEmpty()){
        Node cur = queue.poll();
        System.out.printIn(cur.value);
        if(cur.left != null){
            queue.add(cur.left);
        }
        if(cur.right != null){
            queue.add(cur.right);
        }
    }
}

求一颗二叉树的宽度

题目分析

以下面的二叉树为例:

image.png

这个二叉树的最大宽度是3,位于第三层。

在上述对二叉树的宽度优先遍历的基础上,我们还需要在遍历时知道该节点位于第几层,以便于记录每一层中的节点个数。

public static void w(Node head){
    if(head == null){
        return;
    }
    Queue<Node> queue = new LinkedList<>();
    queue.add(head);
    HashMap<Node, Integer> levelMap = new HashMap<>();
    levelMap.put(head, 1);
    int curLevel = 1;
    int curLevelNodes = 0;
    int max = Integer.MIN_VALUE;
    while(!queue.isEmpty()){
        Node cur = queue.poll();
        int curNodeLevel = levelMap.get(cur);
        if(curNodeLevel == curLevel){
            curLevelNodes++;
        }else{
            curLevel++;
            curLevelNodes=1;
        }
        max = Math.max(max, curLevelNodes);
        if(cur.left != null){
            levelMap.put(cur.left, curNodeLevel+1);
            queue.add(cur.left);
        }
        if(cur.right != null){
            levelMap.put(cur.right, curNodeLevel+1);
            queue.add(cur.right);
        }
    }
    return max
}

进阶:Leetcode- 662. 二叉树最大宽度

根据上面的例子,这道题好像也是广度优先遍历的一个例子,在其广度优先遍历的基础上,遍历时知道该节点位于哪一层,并记录该层的节点个数,但是好像,此法不通...因为它中间空的位置也要计算!

难点:两端点之间的null节点也计入长度

此时,我们可以利用完全二叉树的性质:

  • 对于一颗完全二插树,如果按照从上至下,从左往右对所有节点从零开始顺序编号
  • 则父节点的左孩子节点的序号:2i+1
  • 父节点的左孩子节点的序号:2i+2
var widthOfBinaryTree = function(root) {
    // 首先实现广度优先遍历,在其基础上,遍历时知道该节点位于哪一层,并记录该层的节点个数
    // 难点:两端点之间的null节点也计入长度
    // const queue = [root];
    // while(queue.length){
    //     const cur = queue.shift();
    //     console.log(cur.val);
    //     cur.left && queue.push(cur.left);
    //     cur.right && queue.push(cur.right);
    // }

    // 如果两端点之间的null节点不计入长度
    // const queue = [root];
    // const levelMap = new Map();
    // let curLevel = 1;
    // let max = 0;
    // let curLevelNodes = 0;
    // levelMap.set(root, 1);
    // while(queue.length>0){
    //     const cur = queue.shift();
    //     const curNodeLevel = levelMap.get(cur);
    //     if(curNodeLevel === curLevel){
    //         curLevelNodes++;
    //     }else{
    //         curLevel++;
    //         curLevelNodes = 1;
    //     }
    //     max = Math.max(max, curLevelNodes);
    //     if(cur.left){
    //         queue.push(cur.left);
    //         levelMap.set(cur.left, curNodeLevel+1);
    //     }
    //     if(cur.right){
    //         queue.push(cur.right);
    //         levelMap.set(cur.right, curNodeLevel+1)
    //     }
    //     console.log(cur, curNodeLevel, curLevel, curLevelNodes, max) ;
    // }
    // return max

    const max = [];
    function dfs(node, dep, idx) {
        if (!node) return;
        max[dep] = (max[dep] || [idx, idx]);
        max[dep][0] = Math.min(max[dep][0], idx);
        max[dep][1] = Math.max(max[dep][1], idx);
        dfs(node.left, dep + 1, (idx << 1) + 1);
        dfs(node.right, dep + 1, (idx << 1) + 2);
    }
    dfs(root, 0, 0);
    return max.reduce((max, [l, r]) => Math.max(max, r - l), 0) + 1;
};