2049. 统计最高分的节点数目(建图+DFS)

190 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

不是因为看到了希望才坚持,而是因为坚持了才能看到希望。共勉

每日刷题第61天 2021.03.11

2049. 统计最高分的节点数目

题目描述

  • 给你一棵根节点为 0 的 二叉树 ,它总共有 n 个节点,节点编号为 0 到 n - 1 。同时给你一个下标从 0 开始的整数数组 parents 表示这棵树,其中 parents[i] 是节点 i 的父节点。由于节点 0 是根,所以 parents[0] == -1 。
  • 一个子树的 大小 为这个子树内节点的数目。每个节点都有一个与之关联的 分数 。求出某个节点分数的方法是,将这个节点和与它相连的边全部 删除 ,剩余部分是若干个 非空 子树,这个节点的 分数 为所有这些子树 大小的乘积 。
  • 请你返回有 最高得分 节点的 数目 。

提示

  • n == parents.length
  • 2 <= n <= 105
  • parents[0] == -1
  • 对于 i != 0 ,有 0 <= parents[i] <= n - 1
  • parents 表示一棵二叉树。

解题思路

  • 由于“树”的性质是,每去掉一条边,就会增加一个连通分量,因此去掉的边数等于得到的子树数量 + * 注意到去掉一个结点本身所连的边的时候,最多将整个树分为四个子树:结点本身、左子树、右子树、父节点的剩下部分。为了计算每个结点的“分数”,我们只需要计算左子树、右子树和父结点部分的大小即可。
    • 要得到这些信息,我们只需要知道以每个结点为根的树的大小,那么一个结点的分数为:以左子结点为根的树大小 × 以右子结点为根的树大小 × (整个树大小 − 以当前结点为根的树大小),以左子结点为根的树大小×以右子结点为根的树大小×(整个树大小−以当前结点为根的树大小)
    • 而:以一个结点为根的树的大小 = 以左子结点为根的树大小 + 以右子结点为根的树大小 + 1,以一个结点为根的树的大小=以左子结点为根的树大小+以右子结点为根的树大小+1
  • 计算一个结点为根的树大小,需要依赖于两个子树,因此我们需要将树进行拓扑排序,然后再按从叶子到根的顺序计算。本例使用 DFS 进行拓扑排序。

AC代码

var countHighestScoreNodes = function (parents) {
    for (let i = 0; i < parents.length; i++) {
        const item = parents[i];
        if (i > 0) {
            obj[i].parent = obj[item]
            if (obj[item].left) {
                obj[item].right = obj[i]
            } else {
                obj[item].left = obj[i]
            }
        }
    }

    function search(node) {
        if (node.left !== null) {
            let leftCounter = search(node.left)
            node.leftCounter = Math.max(node.leftCounter, leftCounter)
        }
        if (node.right !== null) {
            let rightCounter = search(node.right)
            node.rightCounter = Math.max(node.rightCounter, rightCounter)
        }
        return node.leftCounter + node.rightCounter + 1
    }
    search(obj[0])

    let max = 0
    let arr = []
    for (let i = 0; i < parents.length; i++) {
        const item = obj[i]
        let temp = 0
        if (i === 0) {
            temp = (item.leftCounter || 1) * (item.rightCounter || 1)
        } else {
            if (item.parent.left === item) {
                temp = (item.leftCounter || 1) * (item.rightCounter || 1) * (parents.length - (item.leftCounter + item.rightCounter + 1))
            } else {
                temp = (item.leftCounter || 1) * (item.rightCounter || 1) * (parents.length - (item.leftCounter + item.rightCounter + 1))
            }
        }
        max = Math.max(temp, max)
        arr.push(temp)
    }
    return arr.reduce((sum, item) => {
        item === max && (sum++)
        return sum
    }, 0)
};

总结

  • 建图的过程中,还存在一些问题,需要多注意
  • 例如建图的左右节点的方式