力扣1819. 序列中不同最大公约数的数目

该博客讨论了一道LeetCode难题,涉及计算给定正整数数组所有非空子序列的不同最大公约数数量。通过反向思考,从结果角度出发,博主提出从1到最大数值枚举可能的最大公约数,并检查这些数是否为子序列的最大公约数。通过遍历数组中每个数的倍数,利用最大公约数性质,逐步增加子序列元素,找到符合条件的子序列。最终给出C++代码实现来解决这个问题。
摘要由CSDN通过智能技术生成

1819. 序列中不同最大公约数的数目
题解

给你一个由正整数组成的数组 nums 。

数字序列的 最大公约数 定义为序列中所有整数的共有约数中的最大整数。

例如,序列 [4,6,16] 的最大公约数是 2 。
数组的一个 子序列 本质是一个序列,可以通过删除数组中的某些元素(或者不删除)得到。

例如,[2,5,10][1,2,1,2,4,1,5,10] 的一个子序列。
计算并返回 nums 的所有 非空 子序列中 不同 最大公约数的 数目 。

 

示例 1:


输入:nums = [6,10,3]
输出:5
解释:上图显示了所有的非空子序列与各自的最大公约数。
不同的最大公约数为 610321 。
示例 2:

输入:nums = [5,15,40,5,6]
输出:7
 

提示:

1 <= nums.length <= 105
1 <= nums[i] <= 2 * 105

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-different-subsequences-gcds
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

1、不可能枚举每个子序列,再从子序列中求最大公约数
2、转换角度,假设最大公约数为x,判断是否满足题目中的条件(PS:发现好多困难题目的做法都是这样,正着做做不出来,得反着来从结果的角度想
3、最大公约数的枚举范围为1到m,m为最大数值
4、检查此时x是否为子序列的最大公约数
5、方法:
a、最大公约数只能存在它的倍数中这个很容易理解,因此遍历的部分只是当前倍数存在于数组的数
b、这样的子序列中数字越多,最大公约数越小;反之也成立。原因是当前子序列中的数字必定大于x,因为都是x的倍数。假设4,8,最大公约数为4,增加一个数字6,最大公约数变为2,说明2的倍数越多时,最大公约数只会变小,不会变大,因此2此时就是这样的子序列的最小公约数。
c、利用这个特性,选取所有的x的倍数,求他们的最大公约数,不断地增加数目,gcd(a,b,c) = gcd(gcd(a,b),c),此时得到的最大公约数如果等于x,那么x就为所求(为什么一定要选所有的倍数?因为假如我们只选取其中的几个,此时由于规律b,最大公约数只会变大,又因为我们枚举可能的答案时是从小往大的,因此较大的公约数会在后面的枚举中出现

class Solution {
public:
    bool f[200001];
    int mx;
    int gcd(int a,int b){
        return b != 0?gcd(b,a % b):a;
    }
    bool check(int x){
        int t = 0;
        for(int i = x;i <= mx;i += x){
            if(f[i]){
                if(t == 0)t = i;
                else t = gcd(t,i);
            }
        }
        return t == x;
    }
    int countDifferentSubsequenceGCDs(vector<int>& nums) {
        memset(f,false,sizeof(f));
        for(int i = 0;i < nums.size();++i){
            f[nums[i]] = true;
        }
        mx = *max_element(nums.begin(),nums.end());
        int ans = 0;
        for(int i = 1;i <= mx;++i){
            if(check(i)){
                ans++;
            }
        }
        return ans;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值