【每日一题Day87】LC1819序列中不同最大公约数的数 | 数学

文章介绍了如何解决LeetCode上的一个问题,即计算给定正整数数组nums中所有非空子序列的不同最大公约数(GCD)。通过枚举最大公约数并判断是否存在子序列满足条件,同时优化循环边界,最终计算出不同GCD的个数。文章提供了两种解决方案,一种是未优化的时间复杂度为O(n+maxlog(max)),另一种优化后的时间复杂度降低到O(n+max/3)。
摘要由CSDN通过智能技术生成

序列中不同最大公约数的数【LC1819】

You are given an array nums that consists of positive integers.

The GCD of a sequence of numbers is defined as the greatest integer that divides all the numbers in the sequence evenly.

  • For example, the GCD of the sequence [4,6,16] is 2.

A subsequence of an array is a sequence that can be formed by removing some elements (possibly none) of the array.

  • For example, [2,5,10] is a subsequence of [1,2,1,**2**,4,1,**5**,**10**].

Return the number of different GCDs among all non-empty subsequences of nums.

错过周赛了 送俺大侄子去医院了 找时间虚拟一下
(什么错过了… 又记错时间 真滴无语)

  • 思路:

    • 由于数组中的最大公约数不可能超过子序列的最大值,因此可以枚举所有可能的最大公约数来判断当前的公约数是否有子序列构成。
    • 那么如何判断是否有子序列能够得到当前枚举的gcd值呢?
      • 首先最大公约数为x的子序列一定都是x的倍数,但是都是x的倍数的最序列的最大公约数不一定是x,但最大公约数一定是x的倍数,比如子序列[6,12]都是3的倍数,最大公约数为6。
      • 因此枚举所有x的倍数,若存在于nums中则添加至当前子序列中,更新最大公约数gcd,若gcd==x,那么退出循环,个数加1。
        • 随着子序列个数的增加,最大公约数只可能减小或者不变,因此当gcd==x时,退出循环即可
  • 实现

    class Solution {
        public int countDifferentSubsequenceGCDs(int[] nums) {
            int max = 0, count = 0;
            for (int num : nums){
                max = Math.max(max, num);
            }
            boolean[] map = new boolean[max + 1];
            for (int num : nums){
                map[num] = true;
            }
            for (int i = 1; i <= max; i++){
                int gcd = 0;
                for (int j = i; j <= max; j += i){
                    if (map[j]) gcd = gcd(gcd, j);
                }
                if (gcd == i) count++;
            }
            return count;
        }
        public int gcd (int x, int y){
            while (y != 0){
                int tmp = x;
                x = y;
                y = tmp % y;
            }
            return x; 
        }
    }
    
    • 复杂度分析

      • 时间复杂度: O ( n + m a x l o g ( m a x ) O(n+maxlog(max) O(n+maxlog(max),假设数组中元素的最大值为 m a x max max
      • 空间复杂度: O ( m a x ) O(max) O(max)
  • 优化:将答案分为两部分

    • 子序列的长度为1,此时最大公约数等于 n u m s [ i ] nums[i] nums[i],对答案的恭喜为nums中不同元素的个数
    • 子序列的长度为2,为了避免重复计算,此时的最大公约数i必须不在nums中。此外,如果最大公约数为 i i inums中最小要有 2 i 2i 2i 3 i 3i 3i两个数,因此i只需要枚举至 m a x 3 \frac {max}{3} 3max
    class Solution {
        public int countDifferentSubsequenceGCDs(int[] nums) {
            int ans = 0, mx = 0;
            for (int x : nums) mx = Math.max(mx, x);
            var has = new boolean[mx + 1];
            for (int x : nums)
                if (!has[x]) {
                    has[x] = true;
                    ++ans; // 单独一个数也算
                }
            for (int i = 1; i <= mx / 3; ++i) { // 优化循环上界
                if (has[i]) continue;
                int g = 0; // 0 和任何数 x 的最大公约数都是 x
                for (int j = i * 2; j <= mx && g != i; j += i) // 枚举 i 的倍数 j
                    if (has[j]) // 如果 j 在 nums 中
                        g = gcd(g, j); // 更新最大公约数
                if (g == i) ++ans; // 找到一个答案
            }
            return ans;
        }
    
        private int gcd(int a, int b) {
            while (a != 0) {
                int tmp = a;
                a = b % a;
                b = tmp;
            }
            return b;
        }
    }
    
    作者:灵茶山艾府
    链接:https://leetcode.cn/problems/number-of-different-subsequences-gcds/solutions/2061079/ji-bai-100mei-ju-gcdxun-huan-you-hua-pyt-get7/
    来源:力扣(LeetCode)
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值