[解题报告]《算法零基础100讲》(第13讲) 最大公约数

零、写在前面

         这是打卡的第十三天,主要内容在

《算法零基础100讲》(第13讲) 最大公约数https://blog.csdn.net/WhereIsHeroFrom/article/details/121092685https://blog.csdn.net/WhereIsHeroFrom/article/details/121092685

 一、主要知识点

       1. 模运算的运算法则

        

         其实就是取模运算对四则运算和幂运算的次序无关性。先取模后取模还是同时取模结果都相同。

        2.最大公约数

                两个数a、b的最大公约数定义为能同时被a、b整除的最大数字,记为gcd(a,b);

        3.辗转相除法

                这部分其实高中学过。

                 递推的时候可以发现后面两个数字的位置发生了变化,这才体现辗转是不是?

                其中b如果一开始就等于0的话返回的是a(划重点,要考!)


 二、课后习题详解

1979. 找出数组的最大公约数

1979. 找出数组的最大公约数https://leetcode-cn.com/problems/find-greatest-common-divisor-of-array/

思路

题目说了求最大最小值的公因数,所以我们就分两步

  1. 求最大最小值
  2. 求这俩的最大公约数

 其实没啥难度,看代码参考吧

int findGCD(int* nums, int numsSize){
    int max = nums[0], min = nums[0] ;
    for(int i = 0; i < numsSize; i++){
        if(max < nums[i])   max = nums[i];
        if(min > nums[i])   min = nums[i];
    }
    for(int i = min; i >=1; --i)
        if(!((min % i) || (max % i))) return i;
    return 0;
}

 结果分析

还行还行。。


 1819. 序列中不同最大公约数的数目(这个有点难。。。真的!)

1819. 序列中不同最大公约数的数目https://leetcode-cn.com/problems/number-of-different-subsequences-gcds/

思路

        这题是不可能去看所有序列的最大质数然后计算的,不然的时间复杂度过高,会超时。

        比较科学的方法是类似于素数筛的方式枚举所有可能的数然后做验证。

        所有可能的数字其实比较好得到就是1-最大的数字,然后怎么验证它是否是序列的一个最大公约数就会显的比较困难。

        我们知道多个数的最大公约数其实可以进行分步计算,比如a、b、c三个数的最大公约数我们可以先求出a、b的最大公约数d,然后再求d和c的最大公约数,也就是三个数字的最大公约数。我们对其进行一个推广,那么就可以得到这系列数字的最大公约数。

        然后我们判断这个数x是不是这个序列的自序列的最大公约数,需要分两步。

  1. 找出序列中所有的x的倍数的元素(x的倍数的最大公约数是>=x的)
  2. 判断这些数字的最大公约数是否是x(利用上面说到的两两求解判断序列最大公约数是否是x)

        求解过程我们分成两步。

  1. 将所有不重复元素标记为一个解,并标记对应的数组(方便之后的查找),并将ans加所有不重复数字的个数,并记录所有元素的最大值。
  2. 从1到最大值进行枚举。看是否是自序列的一个公约数,如果是则ans++,同时如果已经标记为解直接跳过。

最终的ans就是所求解。

int gcd(int a, int b){//判断两个数字的最大公约数
    return !b ? a : gcd( b , a % b);
}
int countDifferentSubsequenceGCDs(int* nums, int numsSize){
    bool f[200001] = {0};
    int max = 0 , ans = 0;

    for(int i = 0;i < numsSize;++i){
        if(nums[i] > max) max = nums[i];//确定最大值
        if(!f[nums[i]]){
            ans ++; //将每个元素加进去
            f[nums[i]]++;//标记元素为可行解
        }
    }

    for(int i = 1;i <= max;++i){
        if(f[i]) continue;  //已加入元素
        int g = 0,j;          //0和任何数求最大公约数会得到那个数字 不信你跑跑-.-
        for(j = i; j <= max;j += i){//看所有的i的倍数是否在序列中
            if(f[j]){
                g = gcd(j,g); //求最大的公约数
                if(g == i)  break;
            }
        }
        if(g == i) ans++;    //存在子序列的最大公约数为i
    }

    return ans;
}

结果分析

 可以了可以了,需要注意一个点就是我用的bool类型进行计数,它会自己初始化为0。当然不放心可以使用memset进行初始化。


今日总结

每天的题目都还是挺有挑战的,能够保证基础入门和进阶一点的平衡,英雄哥还是很厉害的。让我们一起快乐刷题0.0

平板刷题不舒服,尝试给安卓平板刷个win11玩玩0.0

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

XingleiGao

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

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

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

打赏作者

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

抵扣说明:

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

余额充值