Leetcode C++ 《第198场周赛-2》 1519. 子树中标签相同的节点数

好久没做题目了,感觉战斗力下降不少,不过有点弯弯绕绕的题目整出来还是很有成就感的~
该学习新东西啦,脚踏实地,总会离我的星辰更进一步~

题目

给你一棵树(即,一个连通的无环无向图),这棵树由编号从 0 到 n - 1 的 n 个节点组成,且恰好有 n - 1 条 edges 。树的根节点为节点 0 ,树上的每一个节点都有一个标签,也就是字符串 labels 中的一个小写字符(编号为 i 的 节点的标签就是 labels[i] )

边数组 edges 以 edges[i] = [ai, bi] 的形式给出,该格式表示节点 ai 和 bi 之间存在一条边。

返回一个大小为 n 的数组,其中 ans[i] 表示第 i 个节点的子树中与节点 i 标签相同的节点数。

树 T 中的子树是由 T 中的某个节点及其所有后代节点组成的树。

示例 1:

树的构造图点击链接看好啦

输入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], labels = “abaedcd”
输出:[2,1,1,1,1,1,1]
解释:节点 0 的标签为 ‘a’ ,以 ‘a’ 为根节点的子树中,节点 2 的标签也是 ‘a’ ,因此答案为 2 。注意树中的每个节点都是这棵子树的一部分。
节点 1 的标签为 ‘b’ ,节点 1 的子树包含节点 1、4 和 5,但是节点 4、5 的标签与节点 1 不同,故而答案为 1(即,该节点本身)。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-nodes-in-the-sub-tree-with-the-same-label
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

  • 根据边的关系构造这棵树,然后计算每个节点的标签在其子树中的出现次数
  • 优化:这棵树不需要用node建出来,了解边的关系,可以通过dfs计算子树中小写字母出现的次数即可
  • 时间复杂度n+e

代码1

class Solution {
public:
    vector<vector<int>> rls;
    vector<vector<int>> counts;
    vector<int> mark;
    string treeLabels;
    vector<int> countSubTrees(int n, vector<vector<int>>& edges, string labels) {
        //其实这棵树完全可以不构造出来,只需要了解其边的关系即可
        //因为每个节点的字符是a-z,所以每个节点统计a-z出现的次数

        for (int i = 0; i < n; i++) {
            vector<int> temp;
            rls.push_back(temp);
        }

        //优化2
        counts.assign(n, vector<int>(26));
        mark.assign(n, 0);

        /*for (int i = 0; i < edges.size(); i++) {
            rls[edges[i][0]].push_back(edges[i][1]);
            rls[edges[i][1]].push_back(edges[i][0]);
        }*/
        //优化1
        for (const auto &edge: edges) {
            rls[edge[0]].push_back(edge[1]);
            rls[edge[1]].push_back(edge[0]);
        }
        treeLabels = labels;
        dfs(0);
        vector<int> res;
        for (int i = 0; i < n; i++) {
            res.push_back(counts[i][labels[i]-'a']);
        }

        return res;
    }

    void dfs(int nodeIndex) {
        //cout << nodeIndex << "  dfs" << endl;
        mark[nodeIndex] = 1;
        vector<int> childs = rls[nodeIndex];
        for (int i = 0; i < childs.size(); i++) {
            //cout << "---- " << childs[i] << "  child" << endl;
            if (mark[childs[i]] == 0) {
                dfs(childs[i]);
                for (int j = 0; j < 26; j++) {
                    counts[nodeIndex][j] += counts[childs[i]][j];
                }
            }
        }
        counts[nodeIndex][treeLabels[nodeIndex]-'a']++;
    }
};

代码2

struct TreeNode1 {
    char c;
    vector<TreeNode1*> children;
    int nums;
};

class Solution {
public:
    vector<int> countSubTrees(int n, vector<vector<int>>& edges, string labels) {
        unordered_map<int, TreeNode1*> tree;
        unordered_map<int, vector<int>> rls;
        for (int i = 0; i < n; i++) {
            rls[i] = vector<int>();
            TreeNode1* t = new TreeNode1();
            t->c  = labels[i];
            vector<TreeNode1*>  tChilds;
            t->children = tChilds;
            t->nums = 0;
            tree.insert(make_pair(i, t));
        }
        for (int i = 0; i < edges.size(); i++) {
            vector<int> one = edges[i];
            rls[one[0]].push_back(one[1]);
            rls[one[1]].push_back(one[0]);
        }

        int* mark = new int[n];
        for (int i = 0; i < n; i++)
            mark[i] = 0;
        queue<int>  nodes;
        nodes.push(0);
        mark[0] = 1;
        while(!nodes.empty()) {
            int first = nodes.front();
            nodes.pop();
            vector<int>  chs =  rls[first];
            for (int i = 0; i < chs.size(); i++){
                if (mark[chs[i]] == 0) {
                    tree[first]->children.push_back(tree[chs[i]]);
                    nodes.push(chs[i]);
                    mark[chs[i]] = 1;
                }    
            }
        }
        vector<int> res;
        /*for (int i = 0; i < n; i++) {
            res.push_back(findNum(tree[i], tree[i]->c));
        }*/
        getNum(tree[0]);
        for (int i = 0; i < n; i++) {
            res.push_back(tree[i]->nums);
        }


        return res;
    }

    int findNum(TreeNode1* root, char key) {
        int res = 0;
        if (root == NULL)
            return 0;
        queue<TreeNode1*>  nodes;
        nodes.push(root);
        while(!nodes.empty()) {
            TreeNode1* first = nodes.front();
            nodes.pop();
            if (first->c == key)
                res++;
            vector<TreeNode1*>  chs =  first->children;
            for (int i = 0; i < chs.size(); i++){
                nodes.push(chs[i]);
            }
        }
        return res;
    }
    //优化了计算label
    vector<int> getNum(TreeNode1* root) {
        vector<int> res;
        for (int i = 0; i < 26; i++) {
            res.push_back(0);
        }
        if (root == NULL) {
            return res;
        }
        vector<TreeNode1*>  chs =  root->children;
        for (int i = 0; i < chs.size(); i++) {
            vector<int> t = getNum(chs[i]);
            for (int i = 0; i < 26; i++) {
                res[i] += t[i];
            }
        }
        res[root->c-'a']++;
        root->nums = res[root->c-'a'];
        return res;
    }
};

  • 我明明优化了整个大框架的思路,还是没A,最后用了auto以及vector的assignA掉了它,对leetcode的时间边界感到绝望
  • 不用构建树的,我实在的构建出来一棵树,好大好占空间啊
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值