题目描述

✅ 1250. 检查「好数组」

image-20260929075917998

题意分析

从正整数数组中选择一些元素,每个选中元素可以乘任意整数系数,再把结果相加。判断是否能恰好得到一,能则返回真,否则返回假。

系数可以为正数、负数或零,因此不是只做正数相加的子集和问题。没有选择的元素等价于系数取零,可以统一考虑整个数组的整数线性组合;只需判断存在性,不需要输出系数。

解法:最大公约数判定

核心思路

[!blue]

设全部元素的最大公约数为 g。因为 g 整除每个元素,也整除它们的任意整数倍及这些倍数之和,所以所有可能结果都必须是 g 的倍数。若能得到一,必然有 g = 1,这是必要条件。

反方向由裴蜀定理保证:若干整数的最大公约数本身可以表示成这些整数的整数系数之和。因此 g = 1 时,一定存在题目允许的系数组合得到一,必要条件同时也是充分条件。

这个结论也能从辗转相除理解:每步余数都是 a - q * b,仍然是旧参数的整数线性组合,最终得到的最大公约数可以反向表示成最初两个数的组合。再将这个公约数与下一个数求公约数,逐次代入,就能推广到整个数组,不需要某一对数先互质。

代码逐个维护已经扫描元素的最大公约数。初值设为零,利用 gcd(0, x) = x 统一处理首项;一旦得到一,后面继续与任何正整数求公约数都仍为一,可以直接返回。若扫描完仍大于一,全部组合都被这个公因子约束,无法得到一。

解题步骤

  1. 将累计最大公约数 g 初始化为零。
  2. 逐个读取数组元素,更新 g = gcd(g, num)。
  3. 求两数公约数时反复将 (a, b) 更新为 (b, a % b),直到第二项为零,返回第一项。
  4. 累计结果为一时立即返回 true。
  5. 全部元素处理完仍未达到一,返回 false。

代码实现

class Solution {
    public boolean isGoodArray(int[] nums) {
        // gcd(0,x)=x,统一处理首个元素。
        int g = 0;

        for (int num : nums) {
            g = gcd(g, num);

            // 累计最大公约数成为一后,继续加入元素也不会改变。
            if (g == 1) {
                return true;
            }
        }

        return false;
    }

    private int gcd(int a, int b) {
        while (b != 0) {
            // 先保留旧参数的余数,再更新两个参数。
            int remainder = a % b;

            a = b;
            b = remainder;
        }

        return a;
    }
}
func isGoodArray(nums []int) bool {
    // gcd(0,x)=x,统一处理首个元素。
    g := 0
    for _, num := range nums {
        g = gcd(g, num)
        // 累计最大公约数成为一后,继续加入元素也不会改变。
        if g == 1 {
            return true
        }
    }
    return false
}

func gcd(a, b int) int {
    for b != 0 {
        a, b = b, a%b
    }
    return a
}

复杂度分析

  • 时间复杂度:上界为 $O(n\log(C+1))$,C 为最大元素,最多进行 n 次辗转相除,每次最多对数级取余操作。
  • 空间复杂度:$O(1)$,迭代维护两个取余参数和一个累计结果,无需存储系数或子集。

关键点总结

[!green]

  • 公因子整除全部线性组合,给出必须满足的条件。
  • 裴蜀定理保证最大公约数本身可表示,补上存在性的反向证明。
  • 允许负系数和零系数,使问题能够直接使用整数线性组合结论。
  • 检查整个数组的累计公约数,不能只检查是否含一或是否存在一对互质数。

易错点总结

[!yellow]

  • 把系数限制为非负数,误变成只加不减的选择问题,无法使用当前判定结论。
  • 只检查数组有没有一,没有一的数组仍可能通过正负整数系数组合得到一。
  • 只找一对互质元素,不同元素共同参与后,整体公约数也可能才降为一。
  • 将累计公约数初始化为一,后续任何输入都会维持一,导致全部误判成功。
  • 在计算余数之前覆盖旧参数,会丢失原来的 a % b,破坏辗转相除。

相似题目

题目 难度 关联与区别
365. 水壶问题 中等 两题都由最大公约数刻画可表示的整数,本题要求整数线性组合恰好得到1。
补充题 154. 最大公约数 简单 对全数组逐项求gcd,最终为1即可;无需搜索每个元素的整数系数。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2023/20991398
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!