快捷搜索: 王者荣耀 脱发

Leetcode P1782 统计点对的数目

Leetcode P1782 统计点对的数目

给你一个无向图,无向图由整数 n ,表示图中节点的数目,和 edges 组成,其中 $edges[i] = [u_i, v_i] $表示 u i u_i ui 和 v i v_i vi 之间有一条无向边。同时给你一个代表查询的整数数组 queries 。

第 j 个查询的答案是满足如下条件的点对 (a, b) 的数目:

    a < b cnt 是与 a 或者 b 相连的边的数目,且 cnt 严格大于 queries[j] 。

请你返回一个数组 answers ,其中 answers.length == queries.length 且 answers[j] 是第 j 个查询的答案。

请注意,图中可能会有 重复边 。

示例1:

输入:n = 4, edges = [[1,2],[2,4],[1,3],[2,3],[2,1]], queries = [2,3]
输出:[6,5]

示例2:

输入:n = 5, edges = [[1,5],[1,5],[3,4],[2,5],[1,3],[5,1],[2,3],[2,5]], queries = [1,2,3,4,5]
输出:[10,10,9,8,6]

提示:

    2 <= n <= 2 * 10^4 1 <= edges.length <= 10^5 1 <= ui, vi <= n ui != vi 1 <= queries.length <= 20 0 <= queries[j] < edges.length

这是47场双周赛的最后一题,我没有参加,但估计这道题我也不会做。给一个图,统计点对(u,v)的数量,其中(u,v)满足和u或v连边的数量大于cnt。

首先容易想到,和u或v连接的边的数量是: d e g r e e [ u ] + d e g r e e [ v ] − m p [ u ] [ v ] degree[u]+degree[v]-mp[u][v] degree[u]+degree[v]−mp[u][v] 其中degree容易处理得到,代表一个点的度数。mp[u][v]是u和v之间边的数量,本来可以是个二维数组,但这里由于n的范围较大,可以用20001 * u + v代替点对(u,v)。所以,我们要找到满足 d e g r e e [ u ] + d e g r e e [ v ] − m p [ u ] [ v ] > c n t degree[u]+degree[v]-mp[u][v]>cnt degree[u]+degree[v]−mp[u][v]>cnt的点对(u,v)的数量。

暴力穷举显然会被卡。一个巧妙的思路是,先处理得到 d e g r e e [ u ] + d e g r e e [ v ] > c n t degree[u]+degree[v]>cnt degree[u]+degree[v]>cnt的点对数sum1,这个可以用双指针得到。再计算 d e g r e e [ u ] + d e g r e e [ v ] > c n t degree[u]+degree[v]>cnt degree[u]+degree[v]>cnt但 d e g r e e [ u ] + d e g r e e [ v ] − m p [ u ] [ v ] ≤ c n t degree[u]+degree[v]-mp[u][v]leq cnt degree[u]+degree[v]−mp[u][v]≤cnt的点对数量sum2,这样的点对一定在edge数组里,只需要遍历一遍edge就能得到…sum1-sum2即为答案。可以发现,很多数据规模直觉上无法解决的问题,可以分为两部分解决,用双指针巧妙优化。代码如下:

class Solution {
          
   
public:
    vector<int> countPairs(int n, vector<vector<int>>& edges, vector<int>& queries) {
          
   
        vector<int> res(queries.size());
        unordered_map<int, int> mp;
        int d[20010], degrees[20010];
        memset(d, 0, sizeof(d));
        for (auto &edge: edges) {
          
   
            int u = min(edge[0], edge[1]);
            int v = max(edge[0], edge[1]);
            mp[u * 20001 + v]++;
            d[u]++, d[v]++;
        }
        for (int i = 1; i <= n; i++) degrees[i] = i;
        sort(degrees + 1, degrees + n + 1, [&](int a, int b) {
          
   
            return d[a] < d[b];
        });
        for (int i = 0; i < queries.size(); i++) {
          
   
            int cnt = queries[i];
            int r = n, sum1 = 0;
            unordered_set<int> dup;
            for (int l = 1; l < n; l++) {
          
   
                while (r > l && d[degrees[l]] + d[degrees[r]] > cnt) r--;
                sum1 += r > l ? n - r : n - l;
            }
            for (auto &edge: edges) {
          
   
                int u = min(edge[0], edge[1]);
                int v = max(edge[0], edge[1]);
                if (d[u] + d[v] > cnt && d[u] + d[v] - mp[20001 * u + v] <= cnt) dup.insert(20001 * u + v);
            }
            res[i] = sum1 - dup.size();
        }
        return res;
    }
};
经验分享 程序员 微信小程序 职场和发展