给你一个由正整数组成的数组 nums 。
数字序列的 最大公约数 定义为序列中所有整数的共有约数中的最大整数。
例如,序列 [4,6,16] 的最大公约数是 2 。
数组的一个 子序列 本质是一个序列,可以通过删除数组中的某些元素(或者不删除)得到。
例如,[2,5,10] 是 [1,2,1,2,4,1,5,10] 的一个子序列。
计算并返回 nums 的所有 非空 子序列中 不同 最大公约数的 数目 。
示例 1:
输入:nums = [6,10,3]
输出:5
解释:上图显示了所有的非空子序列与各自的最大公约数。
不同的最大公约数为 6 、10 、3 、2 和 1 。
示例 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;
}
};