0619-508. 出现次数最多的子树元素和

87 阅读2分钟

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

给你一个二叉树的根结点 root ,请返回出现次数最多的子树元素和。如果有多个元素出现的次数相同,返回所有出现次数最多的子树元素和(不限顺序)。

一个结点的 「子树元素和」 定义为以该结点为根的二叉树上所有结点的元素之和(包括结点本身)。

示例 1:

image.png

输入: root = [5,2,-3]
输出: [2,-3,4]

示例 2:

image.png

输入: root = [5,2,-5]
输出: [2]

深度优先搜索

我们可以从根结点出发,深度优先搜索这棵二叉树。对于每棵子树,其子树元素和等于子树根结点的元素值,加上左子树的元素和,以及右子树的元素和。

用哈希表统计每棵子树的元素和的出现次数,计算出现次数的最大值 maxCnt\textit{maxCnt},最后将出现次数等于 maxCnt\textit{maxCnt} 的所有元素和返回。

var findFrequentTreeSum = function(root) {
    const cnt = new Map();
    let maxCnt = 0;

    const dfs = (node) => {
        if (!node) {
            return 0;
        }
        const sum = node.val + dfs(node.left) + dfs(node.right);
        cnt.set(sum, (cnt.get(sum) || 0) + 1);
        maxCnt = Math.max(maxCnt, cnt.get(sum));
        return sum;
    }

    dfs(root);
    const list = [];
    for (const [s, c] of cnt.entries()) {
        if (c === maxCnt) {
            list.push(s);
        }
    }
    const ans = new Array(list.length);
    for (let i = 0; i < list.length; ++i) {
        ans[i] = list[i];
    }
    return ans;
};

复杂度分析

  • 时间复杂度:O(n),其中 n 是二叉树的结点个数。深度优先搜索的时间为 O(n)。
  • 空间复杂度:O(n)。哈希表和递归的栈空间均为 O(n)。

算法步骤

  1. 准备几个全局变量:

    • mxOcc: 记录出现元素最多的次数。即“maximum occurrence"。
    • mp:哈希表,用于维护每一个节点元素和出现的次数。
    • ans:用于记录答案数组。
  2. 对于每一个节点,我们首先递归查询其左子树的和,然后再递归查询其右子树的和,加上这个当前节点本身的值,那么就为该节点的元素和

    • cur = dfs(root.left) + dfs(root.right) + root.val
  3. cur = dfs(root.left) + dfs(root.right) + root.val

    • mp[cur] += 1
  4. 将该元素和出现的次数与mxOcc做比较。

    • 如果mp[cur] > mxOcc。那么则说明当前元素和的个数是最多的。于是将mxOcc跟新为当前元素和的数量,即mxOcc = mp[cur],然后重新记录答案数组。ans = [cur]
    • 如果mp[cur] == mxOcc。那么则说明当前元素和的个数刚好达到了最多的出现次数,直接将其元素和加入到答案数组中。ans.append(cur)
  5. 返回当前元素和。所有递归完成后直接返回答案数组即可。

var findFrequentTreeSum = function(root) {
    let mxOcc = 0;
    const mp = new Map();
    let ans = [];

    const dfs = (root) => {
        if(!root) return 0;
        const cur = root.val + dfs(root.left) + dfs(root.right);
        mp.set(cur, (mp.get(cur) || 0) + 1);
        if(mp.get(cur) > mxOcc) {
            mxOcc = mp.get(cur);
            ans = [cur];
        } else if(mp.get(cur) == mxOcc) {
            ans.push(cur);
        }
        return cur;
    }
    dfs(root);
    return ans;
};