【数论】Leetcode1250. 检查「好数组」

122 阅读2分钟

题目描述

给你一个正整数数组 nums,你需要从中任选一些子集,然后将子集中每一个数乘以一个任意整数,并求出他们的和。

假如该和结果为 1,那么原数组就是一个「好数组」,则返回 True;否则请返回 False

示例

输入:nums = [12,5,7,23]
输出:true
解释:挑选数字 5 和 7。
5*3 + 7*(-2) = 1
输入:nums = [29,6,10]
输出:true
解释:挑选数字 29, 61029*1 + 6*(-3) + 10*(-1) = 1
输入:nums = [3,6]
输出:false

提示

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9

题解:数学(裴蜀定理)

证明:「裴蜀定理」百度百科

  • 对任何整数a、b和它们的最大公约数d,对于任意整数x和y,a*x+b*y都一定是d的倍数,特别地,一定存在整数x,y,使ax+by=d成立。
  • 裴蜀定理也可推广到n个整数:设a1,a2,a3......an为n个整数,d是它们的最大公约数,那么存在整数x1......xn使得x1*a1+x2*a2+...xn*an=d。

本题我们即求已给数组任意子集满足d=1就是好数组,注意如下两点:

  • d=1表明子集的最大公约数为1,即互为质数;
  • '任意' 二字表明,整个数组都要满足互为质数;

综上,即求整个数组中所有数的最大公约数是否为1【互为质数】即可。

由于1与任何数字的最大公约数都是1。因此,若在遍历过程中遇到结果为1,可直接返回结果true

class Solution {
    public boolean isGoodArray(int[] nums) {
        int a = 0;
        for(int b : nums) {
            a = gcd(a, b);
            // 【优化】1与任何数字的最大公约数都是1
            if(a == 1) {
                return true;
            }
        }
        return a == 1;
    }

    int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
}