LeetCode:1627. 带阈值的图连通性

文章介绍了LeetCode的一道题目,涉及图的连通性问题。给定n个城市,如果两个城市之间存在一个共同因子大于阈值,则它们之间连通。解题方法包括使用并查集结合暴力遍历或优化遍历策略,通过合并城市根节点来判断连通性。文章提供了两种解题代码实现。
摘要由CSDN通过智能技术生成

每日一题,并查集+暴力yyds!

题目链接:1627. 带阈值的图连通性 - 力扣(LeetCode)

题目信息:

有 n 座城市,编号从 1 到 n 。编号为 x 和 y 的两座城市直接连通的前提是: x 和 y 的公因数中,至少有一个 严格大于 某个阈值 threshold 。更正式地说,如果存在整数 z ,且满足以下所有条件,则编号 x 和 y 的城市之间有一条道路:

1.x % z == 0

2.y % z == 0

3.z > threshold

给你两个整数 n 和 threshold ,以及一个待查询数组,请你判断每个查询 queries[i] = [ai, bi] 指向的城市 ai 和 bi 是否连通(即,它们之间是否存在一条路径)。

返回数组 answer ,其中answer.length == queries.length 。如果第 i 个查询中指向的城市 ai 和 bi 连通,则 answer[i] 为 true ;如果不连通,则 answer[i] 为 false 。

题目解析:

给定n个城市,城市代码分别为1、2、3...n;若两城市间代码符合一个条件【城市代码的最大公因数大于threshold】则能连通,城市间可通过另一个城市进行连通再给定一个城市代码数组queries(其中两两一组),返回一个List<Boolean>数组(其中的值为queries中一组城市之间是否连通)

解题方法:并查集+(暴力||手动筛选)

代码及超详细解析:

方法一:暴力yyds:

class Solution {
    static int[]fa;//定义一个数组存储所有城市代码的根城市代码,第i个fa[i]表示第i个城市与第fa[i]连通
    public List<Boolean> areConnected(int n, int threshold, int[][] queries) {
        fa=new int[n+1];
        for(int i=1;i<=n;i++)fa[i]=i;//初始化所有城市代码,使其根城市代码最开始指向自身
        List<Boolean> answer=new ArrayList<>();//创建返回的List<boolean>
//此处与方法二不同,暴力太香了
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j<=n;j+=i)
            {
                if(getCommonFactor(i,j)>threshold)merge(i,j);
            }
        }
// 
        //判断给定城市代码数组中一组城市是否连通
        for(int[]q:queries)//使用增强for
        {
            if(find(q[0])==find(q[1]))answer.add(true);//两城市代码的根城市代码是否相同
            else answer.add(false);
        }
        return answer;
    }

//查找x城市代码的根城市代码
    public int find(int x)
    {
        if(fa[x]==x)return x;//如果是他本身则返回自身
        fa[x]=find(fa[x]);//压缩路径:find目的是查找根城市,将根城市代码赋给x城市,表示x城市与根城市连通
        return fa[x];//返回根城市代码,用于比较
    }

//连通两个城市的根城市
    public void merge(int i,int j)
    {
        fa[find(i)]=find(j);//将i城市的根城市的根代码改成j城市的根城市代码
    }
//返回两数字最大公因数
    public int getCommonFactor(int a,int b)
    {
        int c=a%b;
        while(c!=0)
        {
            a=b;
            b=c;
            c=a%b;
        }
        return b;
    }
//
}

方法二:手动过滤不符合条件的城市代码,节省时间

class Solution {
    static int[]fa;//定义一个数组存储所有城市代码的根城市代码,第i个fa[i]表示第i个城市与第fa[i]连通
    public List<Boolean> areConnected(int n, int threshold, int[][] queries) {
        fa=new int[n+1];
        for(int i=1;i<=n;i++)fa[i]=i;//初始化所有城市代码,使其根城市代码最开始指向自身
        List<Boolean> answer=new ArrayList<>();//创建返回的List<boolean>
    //【此处分析忽略threshold=0的情况】人工过滤不符合条件的城市代码,从而节省时间
        //i不从0、1开始,j不从0、1、i、i~2i-1开始。
        //i的初始值为threshold+1,因为小于他的城市代码不跟任何城市连通
        //j若从2i之前开始,(i,j)最大公因数为1,不符合threshold>1的情况
        //j增量为i:先找出与i直接连通的城市,若两城市间接连通则两个城市根城市代码一定相同
        for(int i=threshold+1;i<=n;i++)
        {
            for(int j=i*i;j<=n;j+=i)
            merge(i,j);/连通两个城市的根城市代码
        }      
        //判断给定城市代码数组中一组城市是否连通
        for(int[]q:queries)//使用增强for
        {
            if(find(q[0])==find(q[1]))answer.add(true);//两城市代码的根城市代码是否相同
            else answer.add(false);
        }
        return answer;
    }

//查找x城市代码的根城市代码
    public int find(int x)
    {
        if(fa[x]==x)return x;//如果是他本身则返回自身
        fa[x]=find(fa[x]);//压缩路径:find目的是查找根城市,将根城市代码赋给x城市,表示x城市与根城市连通
        return fa[x];//返回根城市代码,用于比较
    }

//连通两个城市的根城市
    public void merge(int i,int j)
    {
        fa[find(i)]=find(j);//将i城市的根城市的根代码改成j城市的根城市代码
    }
}

给定一个整数数组 nums 和一个目标值 target,要求在数组中找出两个数的和等于目标值,并返回这两个数的索引。 思路1:暴力法 最简单的思路是使用两层循环遍历数组的所有组合,判断两个数的和是否等于目标值。如果等于目标值,则返回这两个数的索引。 此方法的时间复杂度为O(n^2),空间复杂度为O(1)。 思路2:哈希表 为了优化时间复杂度,可以使用哈希表来存储数组中的元素和对应的索引。遍历数组,对于每个元素nums[i],我们可以通过计算target - nums[i]的值,查找哈希表中是否存在这个差值。 如果存在,则说明找到了两个数的和等于目标值,返回它们的索引。如果不存在,将当前元素nums[i]和它的索引存入哈希表中。 此方法的时间复杂度为O(n),空间复杂度为O(n)。 思路3:双指针 如果数组已经排序,可以使用双指针的方法来求解。假设数组从小到大排序,定义左指针left指向数组的第一个元素,右指针right指向数组的最后一个元素。 如果当前两个指针指向的数的和等于目标值,则返回它们的索引。如果和小于目标值,则将左指针右移一位,使得和增大;如果和大于目标值,则将右指针左移一位,使得和减小。 继续移动指针,直到找到两个数的和等于目标值或者左指针超过了右指针。 此方法的时间复杂度为O(nlogn),空间复杂度为O(1)。 以上三种方法都可以解决问题,选择合适的方法取决于具体的应用场景和要求。如果数组规模较小并且不需要考虑额外的空间使用,则暴力法是最简单的方法。如果数组较大或者需要优化时间复杂度,则哈希表或双指针方法更合适。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值