【C/C++】508. 出现次数最多的子树元素和

207 阅读4分钟

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


题目链接: 508. 出现次数最多的子树元素和

题目描述

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

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

提示:

  • 节点数在 [1,104][1, 10^4] 范围内
  • 105 Node.val105-10^5 \leqslant Node.val \leqslant 10^5

示例 1:

freq1-tree.jpg

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

示例 2:

freq2-tree.jpg

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

整理题意

题目给定一棵二叉树的根节点,每个节点的所有子节点值的总和(包括本身),作为该节点的 「子树元素和」,求子树元素和出现次数最多的值。如果有多个,返回多个子树元素和的值,并且不限顺序。

解题思路分析

观察题目数据范围,节点数量在 10410^4 以内,节点值在 ±105±10^5 以内,那么子树元素和最大值和最小值不会超过 ±109±10^9int 整型可以存下,不会溢出。

看到涉及图和树的题目,通常情况需要使用到遍历,这时考虑 BFS 广度优先搜索DFS 深度优先搜索

  • 由于涉及求每个节点的子树元素和,这里考虑带返回值的 DFS 深度优先搜索
  • 类似分治,对于每个节点来说,只需考虑自己本身的节点值加上左子树的子树元素和以及右子树的子树元素和,然后作为返回值返回给上一级。
  • map 记录子树元素和的出现次数,同时维护最大的出现次数 m
  • 最后遍历所有节点的子树元素和,将子树元素和出现次数等于 m 的子树元素和作为答案返回。

具体实现

  1. 首先 DFS 深度优先搜索 求每个节点子树元素和出现的次数。
  2. 在遍历过程中用 map 记录每个节点子树元素和的值以及出现的次数,期间维护最大出现次数 m = max(m, mp[res]);
  3. 遍历 map 集合,求子树元素和出现次数等于 m 的子树元素和。

复杂度分析

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

代码实现

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    //m记录子树元素和出现的最大次数
    int m;
    //mp记录子树元素和出现的次数
    map<int, int> mp;
    //带返回值的DFS深度优先搜索
    int dfs(TreeNode* root){
        if(root == NULL) return 0;
        int res = root->val;
        //分治思想
        res += dfs(root->left) + dfs(root->right);
        //记录子树元素和出现次数
        mp[res]++;
        //维护最大出现次数
        m = max(m, mp[res]);
        return res;
    }
public:
    vector<int> findFrequentTreeSum(TreeNode* root) {
        mp.clear();
        //初始化最大次数为0
        m = 0;
        //DFS深度优先搜索求每个节点的子树元素和以及出现的次数
        dfs(root);
        //遍历mp集合中的每个子树元素和
        auto iter = mp.begin();
        vector<int> ans;
        ans.clear();
        while(iter != mp.end()){
            //记录出现次数等于 m 的作为答案返回
            if(mp[iter->first] == m){
                ans.push_back(iter->first);
            }
            iter++;
        }
        return ans;
    }
};

总结

  • 该题有 分治思想,对于每个节点只需考虑自身和左右子树所返回的值,处理好后再将自己的子树元素和作为返回值返回给上一级,而子树也做同样处理,这样就是递归处理子问题。
  • 该题涉及树形模型,通常情况是需要考虑遍历树的,其次再考虑采用何种遍历方法。
  • 测试结果:

微信截图_20220626223309.png

结束语

想要过上自己心仪的生活,成为自己喜欢的样子,方法其实很简单,就是把无数个“今天”过好。不蹉跎时光,以饱满的热情迎接每一件事,让每一天都有滋有味,生活自然会精彩纷呈。新的一天,加油!