力扣每日一题0731-1161. 最大层内元素和

72 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

给你一个二叉树的根节点 root。设根节点位于二叉树的第 1 层,而根节点的子节点位于第 2 层,依此类推。

请返回层内元素之和 最大 的那几层(可能只有一层)的层号,并返回其中 最小 的那个。

示例 1:

iabeahae.bmp

输入:root = [1,7,0,7,-8,null,null]
输出:2
解释:
第 1 层各元素之和为 1,
第 2 层各元素之和为 7 + 0 = 7,
第 3 层各元素之和为 7 + -8 = -1,
所以我们返回第 2 层的层号,它的层内元素之和最大。

示例 2:

输入:root = [989,null,10250,98693,-89388,null,null,null,-32127]
输出:2

深度优先搜索

我们可以采用深度优先搜索来遍历这棵二叉树,递归的同时记录当前的层号。

相比哈希表,这里我们采用效率更高的动态数组来维护每一层的元素之和,如果当前层号达到了数组的长度,则将节点元素添加到数组末尾,否则更新对应层号的元素之和。

然后遍历数组,找到元素之和最大,且层号最小的元素。

var maxLevelSum = function(root) {
    const sum = [];
    const dfs = (node, level) => {
        if (level === sum.length) {
            sum.push(node.val);
        } else {
            sum.splice(level, 1, sum[level] + node.val);
        }
        if (node.left) {
            dfs(node.left, level + 1);
        }
        if (node.right) {
            dfs(node.right, level + 1);
        }
    }
    dfs(root, 0);
    let ans = 0;
    for (let i = 0; i < sum.length; ++i) {
        if (sum[i] > sum[ans]) {
            ans = i;
        }
    }
    return ans + 1; // 层号从 1 开始
};

广度优先搜索

由于计算的是每层的元素之和,用广度优先搜索来遍历这棵树会更加自然。

对于广度优先搜索,我们可以用队列来实现。初始时,队列只包含根节点;然后不断出队,将子节点入队,直到队列为空。

如果直接套用方法一的思路,我们需要在队列中存储节点和节点的层号。另一种做法是一次遍历完一整层的节点,遍历的同时,累加该层的节点的元素之和,同时用这层的节点得到下一层的节点,这种做法不需要记录层号。

为了代码实现的方便,我们可以使用两个动态数组,第一个数组 qq 为当前层的节点,第二个数组 nq\textit{nq} 为下一层的节点。遍历 qq 中节点的同时,把子节点加到 nq\textit{nq} 中。遍历完当前层后,将 qq 置为 nq\textit{nq}

var maxLevelSum = function(root) {
    let ans = 1, maxSum = root.val;
    let q = [];
    q.push(root);
    for (let level = 1; q.length > 0; ++level) {
        const nq = [];
        let sum = 0;
        for (const node of q) {
            sum += node.val;
            if (node.left) {
                nq.push(node.left);
            }
            if (node.right) {
                nq.push(node.right);
            }
        }
        if (sum > maxSum) {
            maxSum = sum;
            ans = level;
        }
        q = nq;
    }
    return ans;
}