【1782. 统计点对的数目】

news2025/1/14 18:35:08

来源:力扣(LeetCode)

描述:

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

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

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

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

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

示例 1:
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 * 104
  • 1 <= edges.length <= 105
  • 1 <= ui, vi <= n
  • ui != vi
  • 1 <= queries.length <= 20
  • 0 <= queries[j] < edges.length

方法一: 二分查找

思路与算法

根据题意可知,每次查询时给定的 queries[j],需要统计满足如下条件的点对 (a, b) 的数目:

  • a < b ;
  • 对于每次查询 queries[j],与节点 a 或者节点 b 相连的边的数目之和严格大于 queries[j]。

设节点 x 的度为 degree[x],我们知道与节点 a 相连的边的数目即为 a 的度数 degree[a],与节点 b 相连的边的数目即节点 b 的度数 degree[b],如果此时节点 a 与节点 b 之间不存在相连的边,则此时与点对 (a, b) 相连的边的数目即为 degree[a] + degree[b]。

  • 需要注意的与节点 a 或者节点 b 相连的边的数目之和则不一定等于 a 的度数与 b 的度数之和,这是因为 a 与 b 之间可能存在相连的边,假设 a 与 b 之间相连边的数目为 cnt(a, b),则此时与点对 (a, b) 相连的边的数目即为 degree[a] + degree[b] − cnt(a, b),这是由于 cnt(a, b) 被计算了两次。

根据以上分析,对于每次查询时,假设当前给定边的查询值为 queries[i],此时最直接的做法是使用双层循环遍历所有的点对 (a, b),然后找到所有满足的点对即可,但此时时间复杂度为 O(n2),按照题目给定的数量会超时。假设给定点 a,则此时点对的另一节点 b 的度数应该大于 queries[i] − degree[b],因此可以考虑利用二分查找在 O(log⁡n) 的时间复杂度找到满足要求的点 b 的数目,同时还需处理 a, b 存在共边的问题,可以分两步进行:

  • 此时首先找到所有满足 degree[a] + degree[b] > queries[i] 的点对数量。二分查找的思路非常简单,假设当前的点 a 的度为 degree[a],则利用二分查找在数组中查找当前度数大于 queries[i] − degree[a] 的节点数量,为了方便计算,需要将 degree 按照从小到大的顺序进行排列即可,利用二分查找大于 queries[i] - degree[a] 的索引为 j,则此时可以与 a 构成符合要求的节点数量为 n − j,按照上述方法找到所有满足要求的点对数量为 total;
  • 其次需要处理 (a, b) 存在共边的问题,即减去重复计算的部分。我们用哈希存储表 cnt 存储不同边的数量,由于所有的边均为无向边,因此边 ab 与 边 ba 为同样的边,此时为了方便处理可以将边 ab 映射到一个整数 a × n + b, (a < b)。遍历所有的边 ab,此时点对 (a,b) 中重复计算边的数目即为 cnt(a, b) 。此时如果点对 (a, b) 减去重复部分后相连边的数目小于等于 queries[i] ,则认为该点对不满足要求,即从当点对 (a, b) 满足: degree[a] + degree[b] − cnt(a, b) ≤ queries[i] total 的记数减 1 ,最终得到的 total 即可本次的查询结果;

根据以上方法找到每次查询的点对数量,并返回结果即可。

代码:

class Solution {
public:
    vector<int> countPairs(int n, vector<vector<int>>& edges, vector<int>& queries) {
        vector<int> degree(n);
        unordered_map<int, int> cnt;
        for (auto edge : edges) {
            int x = edge[0] - 1, y = edge[1] - 1;
            if (x > y) {
                swap(x, y);
            }
            degree[x]++;
            degree[y]++;
            cnt[x * n + y]++;
        }

        vector<int> arr = degree;
        vector<int> ans;
        sort(arr.begin(), arr.end());
        for (int bound : queries) {
            int total = 0;
            for (int i = 0; i < n; i++) {
                int j = upper_bound(arr.begin() + i + 1, arr.end(), bound - arr[i]) - arr.begin();
                total += n - j;
            }
            for (auto &[val, freq] : cnt) {
                int x = val / n;
                int y = val % n;
                if (degree[x] + degree[y] > bound && degree[x] + degree[y] - freq <= bound) {
                    total--;
                }
            }
            ans.emplace_back(total);
        }

        return ans;
    }
};

时间 824ms 击败 43.75%使用 C++ 的用户
内存 186.11MB 击败 42.19%使用 C++ 的用户
复杂度分析

  • 时间复杂度:O(q×(nlog⁡n+m)) ,其中 q 表示查询数组 queries 的铲毒,n 表示给定的节点的数目,m 表示边 edges 的长度。对所有的点的度数排序时需要的时间复杂度为 O(nlogn),每次查询时需要二分查找找到所有符合要求的点对,并同时遍历所有的边,需要的时间为 O(nlogn+m),一共有 q 次查询,因此总的时间复杂度为 O(nlog⁡n+q×(nlog⁡n+m)) = O(q×(nlog⁡n+m))。
  • 空间复杂度:O(n+m) ,其中 n 表示给定的节点的数目,m 表示边 edges 的数目。我们需要存储每个点的度数,需要的空间为 O(n) ,还需统计每条边出现的次数,需要的空间为 O(m),因此总的空间复杂度为 O(n+m)。

方法二: 双指针

思路与算法

方法二的解法思路跟方法一基本一致,唯一需要特殊处理的是找满足 degree[a] + degree[b] > bound 的点对时可以利用双指针来处理:

假设当前从小到大第 i 节点 a 的度为 degree[a] ,我们从后往前找到第一个满足小于等于 bound − degree[a] 的节点索引为 j ,则此时 b ∈ [j + 1, n − 1] 均满足 degree[a] + degree[b] > queries[i] ,则此时与 a 构成满足要求的节点的数目位 n − 1 − j ,为了防止重复计算,此时只取大于 i 且大于 j 的索引,则此时 b ∈ [max⁡(i + 1, j + 1), n − 1] 区间内的索引即可;

代码 :

class Solution {
public:
    vector<int> countPairs(int n, vector<vector<int>>& edges, vector<int>& queries) {
        vector<int> degree(n);
        unordered_map<int, int> cnt;
        for (auto edge : edges) {
            int x = edge[0] - 1, y = edge[1] - 1;
            if (x > y) {
                swap(x, y);
            }
            degree[x]++;
            degree[y]++;
            cnt[x * n + y]++;
        }

        vector<int> arr = degree;
        vector<int> ans;
        sort(arr.begin(), arr.end());
        for (int bound : queries) {
            int total = 0;
            for (int i = 0, j = n - 1; i < n; i++) {
                while (j > i && arr[i] + arr[j] > bound) {
                    j--;
                }
                total += n - 1 - max(i, j);
            }
            for (auto &[val, freq] : cnt) {
                int x = val / n;
                int y = val % n;
                if (degree[x] + degree[y] > bound && degree[x] + degree[y] - freq <= bound) {
                    total--;
                }
            }
            ans.emplace_back(total);
        }

        return ans;
    }
};

时间 696ms 击败 57.81%使用 C++ 的用户
内存 186.10MB 击败 42.19%使用 C++ 的用户
复杂度分析

  • 时间复杂度:O(nlog⁡n+q×(n+m)) ,其中 q 表示查询数组 queries 的铲毒,n 表示给定的节点的数目,m 表示边 edges 的长度。对所有的点的度数排序时需要的时间复杂度为 O(nlog⁡n) ,每次查询时需要遍历所有点的度数,并同时遍历所有的边,需要的时间为 O(n+m) ,一共有 q 次查询,因此总的时间复杂度为 O(nlog⁡n+q×(n+m)) 。
  • 空间复杂度:O(n+m) ,其中 n 表示给定的节点的数目,m 表示边 edges 的数目。我们需要存储每个点的度数,需要的空间为 O(n) ,还需统计每条边出现的次数,需要的空间为 O(m),因此总的空间复杂度为 O(n+m)。
    author:力扣官方题解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/917076.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

display设为inline-block时引发的高度问题,大坑

今天在写小程序&#xff0c;点击让这个遮罩层显示&#xff0c;结果一直下移&#xff0c;莫名其妙。 解决方案&#xff1a; 在元素的CSS中添加&#xff1a;vertical-align: bottom;

minAreaRect 函数新版与旧版对比

minAreaRect 函数 cv2.minAreaRect (InputArray_points) 入参 points 是点的集合&#xff0c;如轮廓 返回值 RotatedRect,带角度的旋转矩形框,其值形如(center(x,y), (width, height), angle of rotation ) center(x,y), (width, height)分别是旋转矩形框中心的坐标和矩…

chrome浏览器账号密码输入框自动填充时背景色不变

处理前 使用延时的方式解决 .login-box input,password:-webkit-autofill .login-box input,password:-webkit-autofill:hover, .login-box input,password:-webkit-autofill:focus, .login-box input,password:-webkit-autofill:active {-webkit-transition-delay: 999999…

【HMS Core】在线语种检测返回结果错误

【关键字】 在线语种检测、机器学习 【问题描述】 集成在线语种检测服务&#xff0c;检测蒙古文之后&#xff0c;返回结果为中文 【问题分析】 1、在线语种服务目前不支持蒙古文&#xff0c;具体可见官网语种支持列表&#xff1a; 【ML Kit】语种检测支持的语言列表 2、目前…

【JAVA毕设|课设】基于SpringBoot+vue的在线考试系统-以计算机网络为例,可自行录入题库-附下载地址

基于SpringBootvue的在线考试系统-以计算机网络为例&#xff0c;可自行录入题库 一、项目简介二、开发环境三、项目技术四、功能结构五、运行截图六、功能实现七、数据库设计八、源码获取 一、项目简介 随着信息技术的迅猛发展&#xff0c;教育行业正面临着巨大的变革和挑战。…

RTP/RTCP的 NACK, PLI,SLI,FIR

1&#xff0c;概述 在网络环境不是太好的情况下&#xff0c;比如网络拥塞比较严重&#xff0c;丢包率可能比较高&#xff0c;简单实用NACK重传的机制&#xff0c;这样就会有大量的RTCP NACK报文&#xff0c;发送端收到相应的报文&#xff0c;又会发送大量指定的RTP报文&#x…

5G NR:PRACH时域资源

PRACH occasion时域位置由高层参数RACH-ConfigGeneric->prach-ConfigurationIndex指示&#xff0c;根据小区不同的频域和模式&#xff0c;38.211的第6.3.3节中给出了prach-ConfigurationIndex所对应的表格。 小区频段为FR1&#xff0c;FDD模式(paired频谱)/SUL&#xff0c;…

【前端从0开始】JavaSript——循环控制语句

循环控制语句 while语句 While 循环会在指定条件为真时循环执行代码块。 While循环&#xff0c;先进行条件判断&#xff0c;再执行循环体的代码 while (条件表达式){循环体 }注意&#xff1a;当前循环中&#xff0c;如果不满足条件&#xff0c;一次都不会执行 var i 1; whi…

利用tidevice+mysql+grafana实现ios性能测试

利用tidevicemysqlgrafana实现ios性能测试 1.什么是tidevice&#xff1f; tidevice是一个可以和ios设备进行通信的工具&#xff0c;提供以下功能&#xff1a; 截图获取手机信息ipa包的安装和卸载根据bundleID 启动和停止应用列出安装应用信息模拟Xcode运行XCTest&#xff0c…

学会Mybatis框架:让你的代码更具灵活性、可维护性、安全性和高效性【二.动态SQL】

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于Mybatis的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.Mybatis动态SQL如何应用 1.需求 2.…

2022美亚杯个人赛复刻

案件详情 于2022年10月&#xff0c;有市民因接获伪冒快递公司的电邮&#xff0c;不慎地于匪徒架设的假网站提供了个人信用咭资料导致经济损失。 警方追查下发现当中一名受骗市民男子李大輝 (TaiFai) 的信用卡曾经被匪徒在区内的商舖购物。 后来警方根据IP地址&#xff0c;锁定…

js实现定时器

用原生js实现一个倒计时效果.最下面有全部源码,需要自取 js语法: setTimeout:定时器 document.getElementById:Document的方法 getElementById()返回一个匹配特定 ID的元素。由于元素的 ID 在大部分情况下要求是独一无二的&#xff0c;这个方法自然而然地成为了一个高效查找特…

第三篇:对话框窗口部件 QDialog

对话框窗口部件 QDialog 对话框&#xff08;Dialog&#xff09;是计算机图形用户界面&#xff08;GUI&#xff09;中的一种常见窗口类型&#xff0c;通常用于与用户进行交互、获取信息、提供反馈或执行特定任务。对话框的主要目的是与用户进行短期的、有限的交互&#xff0c;以…

【校招VIP】产品职位理解之团队的配合和推进

考点介绍&#xff1a; 对于简历上有实习经验的同学&#xff0c;对于团队配合和项目推进是一个非常常见的提问点。产品经理经常会面临项目延期&#xff0c;无法上线的情况。基于此&#xff0c;产品经理应该做些什么来保障项目按时上线呢&#xff1f; 『产品职位理解之团队的配合…

THUHCSI人机语音交互实验室9篇论文被语音旗舰国际会议INTERSPEECH录用

2023年ISCA国际语音通讯学会年会&#xff08;2023 Annual Conference of the International Speech Communication Association, INTERSPEECH 2023&#xff09;将于2023年8月20日-24日在爱尔兰都柏林召开&#xff0c;清华大学人机语音交互实验室&#xff08;THUHCSI&#xff09…

视频监控平台EasyCVR视频汇聚平台档案库房图书馆等可视化管理平台应用场景全面解析

档案是一种特殊的记录留存文献&#xff0c;具有珍贵的精神财富价值。它们是人类活动的真实见证&#xff0c;是辉煌时刻的历史记录&#xff0c;在社会发展和经济建设中发挥着至关重要的作用。 随着市场经济的不断发展和人类文明的飞速推进&#xff0c;档案的价值和作用变得越来…

【广州华锐互动】VR工厂消防安全演习提供了一种全新、生动的安全教育方式

在工业生产环境中&#xff0c;安全永远是首要的考虑因素。近年来&#xff0c;随着科技的发展&#xff0c;虚拟现实(VR)技术在各种领域的应用越来越广泛&#xff0c;包括教育和培训。其中&#xff0c;VR工厂消防安全演习就是一个典型的例子&#xff0c;它为员工提供了一种全新的…

msvcr120.dll丢失的解决方法,win10系统dll报错解决方法

今天&#xff0c;我将和大家分享一个在win10系统中经常遇到的问题&#xff1a;msvcr120.dll丢失。相信很多朋友在使用电脑的过程中都会遇到这个问题&#xff0c;那么如何解决呢&#xff1f;接下来&#xff0c;就让我为大家详细讲解一下解决方法。 首先&#xff0c;我们来了解一…

基于Spark+django的国漫推荐系统--计算机毕业设计项目

近年来&#xff0c;随着互联网的蓬勃发展&#xff0c;企事业单位对信息的管理提出了更高的要求。以传统的管理方式已无法满足现代人们的需求。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;随着各行业的不断发展&#xff0c;基…

pdf怎么转换成图片?用这几种简单方法搞定

pdf怎么转换成图片&#xff1f;PDF作为一种通用的文档格式&#xff0c;广泛应用于各个领域。然而&#xff0c;在某些情况下&#xff0c;我们可能需要将PDF文件转换成图片格式&#xff0c;以便更方便地在网页、社交媒体或演示中使用。下面就给大家介绍三种简单而高效的方法来实现…