使用并查集处理树的路径

力扣312次周赛第四题,我还不会做,记录一下这类题型,代码来自y总。

6191. 好路径的数目

给你一棵 n 个节点的树(连通无向无环的图),节点编号从 0 到 n - 1 且恰好有 n - 1 条边。

给你一个长度为 n 下标从 0 开始的整数数组 vals ,分别表示每个节点的值。同时给你一个二维整数数组 edges ,其中 edges[i] = [ai, bi] 表示节点 ai 和 bi 之间有一条 无向 边。

一条 好路径 需要满足以下条件:

    开始节点和结束节点的值 相同 。
    开始节点和结束节点中间的所有节点值都 小于等于 开始节点的值(也就是说开始节点的值应该是路径上所有节点的最大值)。

请你返回不同好路径的数目。

注意,一条路径和它反向的路径算作 同一 路径。比方说, 0 -> 1 与 1 -> 0 视为同一条路径。单个节点也视为一条合法路径。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-good-paths

思路:

        将树中节点按节点权值排序,从小到大遍历,只能用左边权值比它小的点。

        遍历后将他们加入树中,用并查集表示他们属于的集合,遍历每个集合。

AC代码:

class Solution {
public:
    vector<int> p;

    int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    int numberOfGoodPaths(vector<int>& vals, vector<vector<int>>& edges) {
        int n = vals.size();
        vector<vector<int>> g(n);

        for (auto& e: edges) {
            int a = e[0], b = e[1];
            g[a].push_back(b);
            g[b].push_back(a);
        }

        vector<int> q(n);
        p.resize(n);
        for (int i = 0; i < n; i ++ ) p[i] = q[i] = i;
        sort(q.begin(), q.end(), [&](int a, int b) {
            return vals[a] < vals[b];
        });

        int res = 0;
        for (int i = 0; i < n; i ++ ) {
            int j = i + 1;
            while (j < n && vals[q[i]] == vals[q[j]]) j ++ ;

            for (int k = i; k < j; k ++ ) {
                int x = q[k];
                for (int y: g[x]) {
                    if (vals[x] >= vals[y])
                        p[find(x)] = find(y);
                }
            }

            unordered_map<int, int> hash;
            for (int k = i; k < j; k ++ )
                hash[find(q[k])] ++ ;
            for (auto& [k, v]: hash)
                res += v * (v + 1) / 2;
            i = j - 1;
        }

        return res;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星河边采花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值