Leetcode 1782. 统计点对的数目

这两天实训比较忙,之后补
2023年08月24日 16:10:44 补

题目描述

给你一个无向图,无向图由整数 n ,表示图中节点的数目,和 edges 组成,其中 edges[i] = [ui, vi] 表示 ui 和 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]
解释:每个点对中,与至少一个点相连的边的数目如上图所示。
answers[0] = 6。所有的点对(a, b)中边数和都大于2,故有6个;
answers[1] = 5。所有的点对(a, b)中除了(3,4)边数等于3,其它点对边数和都大于3,故有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]

代码

当然是大佬的代码了(哭)

class Solution {
    public int[] countPairs(int n, int[][] edges, int[] queries) {
        // deg[i] 表示与点 i 相连的边的数目
        var deg = new int[n + 1]; // 节点编号从 1 到 n
        var cntE = new HashMap<Integer, Integer>();
        for (var e : edges) {
            int x = e[0], y = e[1];
            if (x > y) {
                // 交换 x 和 y,因为 1-2 和 2-1 算同一条边
                int tmp = x;
                x = y;
                y = tmp;
            }
            deg[x]++;
            deg[y]++;
            // 统计每条边的出现次数
            // 用一个 int 存储两个不超过 65535 的数
            cntE.merge(x << 16 | y, 1, Integer::sum); // cntE[x<<16|y]++
        }

        var ans = new int[queries.length];
        var sortedDeg = deg.clone();
        Arrays.sort(sortedDeg); // 排序,为了双指针
        for (int j = 0; j < queries.length; j++) {
            int q = queries[j];
            int left = 1, right = n; // 相向双指针
            while (left < right) {
                if (sortedDeg[left] + sortedDeg[right] <= q) {
                    left++;
                } else {
                    ans[j] += right - left;
                    right--;
                }
            }
            for (var e : cntE.entrySet()) {
                int k = e.getKey(), c = e.getValue();
                int s = deg[k >> 16] + deg[k & 0xffff]; // 取出 k 的高 16 位和低 16 位
                if (s > q && s - c <= q) {
                    ans[j]--;
                }
            }
        }
        return ans;
    }
}

大佬优化过的代码

class Solution {
    public int[] countPairs(int n, int[][] edges, int[] queries) {
        var deg = new int[n + 1];
        var cntE = new HashMap<Integer, Integer>();
        for (var e : edges) {
            int x = e[0], y = e[1];
            if (x > y) {
                int tmp = x;
                x = y;
                y = tmp;
            }
            deg[x]++;
            deg[y]++;
            cntE.merge(x << 16 | y, 1, Integer::sum);
        }

        // 统计 deg 中元素的出现次数
        var cntDeg = new HashMap<Integer, Integer>();
        int maxDeg = 0;
        for (int i = 1; i <= n; i++) {
            cntDeg.merge(deg[i], 1, Integer::sum); // cntDeg[deg[i]]++
            maxDeg = Math.max(maxDeg, deg[i]);
        }

        // 2)
        var cnts = new int[maxDeg * 2 + 2];
        for (var e1 : cntDeg.entrySet()) {
            int deg1 = e1.getKey(), c1 = e1.getValue();
            for (var e2 : cntDeg.entrySet()) {
                int deg2 = e2.getKey(), c2 = e2.getValue();
                if (deg1 < deg2)
                    cnts[deg1 + deg2] += c1 * c2;
                else if (deg1 == deg2)
                    cnts[deg1 + deg2] += c1 * (c1 - 1) / 2;
            }
        }

        // 3)
        for (var e : cntE.entrySet()) {
            int k = e.getKey(), c = e.getValue();
            int s = deg[k >> 16] + deg[k & 0xffff];
            cnts[s]--;
            cnts[s - c]++;
        }

        // 4) 计算 cnts 的后缀和
        for (int i = cnts.length - 1; i > 0; i--)
            cnts[i - 1] += cnts[i];

        for (int i = 0; i < queries.length; i++)
            queries[i] = cnts[Math.min(queries[i] + 1, cnts.length - 1)];
        return queries;
    }
}

作者:灵茶山艾府

我的代码

//哈哈哈,这次我就想到一个先遍历找,然后想有关图的东西,然后脑子空空

思路

大佬思路

没错,在上面的链接里

我滴思路

遍历,双指针,啊。。。。啥也不会了,图我还没学明白,一会儿去恶补,再来补!!

posted @   无聊的飞熊  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示