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

题目链接

Leetcode.1819 序列中不同最大公约数的数目 Rating : 2540

题目描述

给你一个由正整数组成的数组 n u m s nums nums

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

  • 例如,序列 [ 4 , 6 , 16 ] [4,6,16] [4,6,16] 的最大公约数是 2

数组的一个 子序列 本质是一个序列,可以通过删除数组中的某些元素(或者不删除)得到。

  • 例如, [ 2 , 5 , 10 ] [2,5,10] [2,5,10] [ 1 , 2 , 1 , 2 , 4 , 1 , 5 , 10 ] [1,2,1,2,4,1,5,10] [1,2,1,2,4,1,5,10] 的一个子序列。

计算并返回 n u m s nums nums 的所有 非空 子序列中 不同 最大公约数的 数目 。

示例 1:

在这里插入图片描述

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

示例 2:

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

提示:
  • 1 < = n u m s . l e n g t h < = 1 0 5 1 <= nums.length <= 10^5 1<=nums.length<=105
  • 1 < = n u m s [ i ] < = 2 ∗ 1 0 5 1 <= nums[i] <= 2 * 10^5 1<=nums[i]<=2105

解法:数论 & 计数

一个长度为 n n n 的数组的子序列个数为 2 n − 1 2^n - 1 2n1,本题 n = 1 0 5 n = 10^5 n=105,所以直接回溯枚举的话肯定会超时。

所以我们可以考虑从 值域 入手。因为 n u m s [ i ] nums[i] nums[i] 最大是 2 × 1 0 5 2\times10^5 2×105,所以 n u m s nums nums 任意一个子序列的最大公约数也肯定是 ≤ 2 × 1 0 5 \leq 2\times10^5 2×105的。

那我们就可以考虑枚举 最大公约数 g g g 的倍数

  • 1 , 2 , 3 , 4 , 5 , 6... 1,2,3,4,5,6... 1,2,3,4,5,6...
  • 2 , 4 , 6 , 8 , 10 , 12... 2,4,6,8,10,12... 2,4,6,8,10,12...
  • 3 , 6 , 9 , 12 , 15 , 18 , . . . 3,6,9,12,15,18,... 3,6,9,12,15,18,...
  • 4 , 8 , 12 , 16 , 20 , 24 , . . . 4,8,12,16,20,24,... 4,8,12,16,20,24,...

我们设值域为 U U U。对于 1 1 1 的倍数需要枚举 ⌊ U 1 ⌋ \lfloor \frac{U}{1} \rfloor 1U次;对于 2 2 2 的倍数需要枚举 ⌊ U 2 ⌋ \lfloor \frac{U}{2} \rfloor 2U次;对于 3 3 3 的倍数需要枚举 ⌊ U 3 ⌋ \lfloor \frac{U}{3} \rfloor 3U次;对于 4 4 4 的倍数需要枚举 ⌊ U 4 ⌋ \lfloor \frac{U}{4} \rfloor 4U次。。。

⌊ U 1 ⌋ + ⌊ U 2 ⌋ + ⌊ U 3 ⌋ + ⌊ U 4 ⌋ . . . + ⌊ U U ⌋ ≤ U × ( 1 1 + 1 2 + 1 3 + 1 4 + . . . + 1 U ) \lfloor \frac{U}{1} \rfloor + \lfloor \frac{U}{2} \rfloor +\lfloor \frac{U}{3} \rfloor +\lfloor \frac{U}{4} \rfloor ...+\lfloor \frac{U}{U} \rfloor \leq U \times (\frac{1}{1} + \frac{1}{2} +\frac{1}{3} + \frac{1}{4}+...+\frac{1}{U} ) 1U+2U+3U+4U...+UUU×(11+21+31+41+...+U1)

( 1 1 + 1 2 + 1 3 + 1 4 + . . . + 1 U ) (\frac{1}{1} + \frac{1}{2} +\frac{1}{3} + \frac{1}{4}+...+\frac{1}{U} ) (11+21+31+41+...+U1)调和级数,这部分是近似于 O ( l o g U ) O(logU) O(logU) 的。

所以对于每一个数 i i i 的倍数,我们判断它是否在 n u m s nums nums 中(通过哈希表快速判断)。如果在数组中,就将它与 g g g (初始 g = 0 g = 0 g=0)取最大公约数。等到循环结束,判断 g = i g = i g=i。如果成立,说明 n u m s nums nums 中确实存在一个 最大公约数为 i i i 的子序列,答案 +1。

时间复杂度: O ( U × l o g U ) O(U\times logU) O(U×logU)

C++代码:

class Solution {
public:
    int countDifferentSubsequenceGCDs(vector<int>& nums) {
        int mx = *max_element(nums.begin(),nums.end());
        vector<bool> st(mx + 1);

        for(auto x:nums) st[x] = true;

        int ans = 0;

        for(int i = 1;i <= mx;i++){
            int g = 0;
            for(int j = i;j <= mx && g != i;j += i){
                if(st[j]) g = gcd(g , j);
            }
            if(g == i) ans++;
        }

        return ans;
    }
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值