{x}
blog image

Check If It Is a Good Array

Given an array nums of positive integers. Your task is to select some subset of nums, multiply each element by an integer and add all these numbers. The array is said to be good if you can obtain a sum of 1 from the array by any possible subset and multiplicand.

Return True if the array is good otherwise return False.

 

Example 1:

Input: nums = [12,5,7,23]
Output: true
Explanation: Pick numbers 5 and 7.
5*3 + 7*(-2) = 1

Example 2:

Input: nums = [29,6,10]
Output: true
Explanation: Pick numbers 29, 6 and 10.
29*1 + 6*(-3) + 10*(-1) = 1

Example 3:

Input: nums = [3,6]
Output: false

 

Constraints:

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

Solution Explanation for Check If It Is a Good Array

This problem revolves around the concept of Bézout's Identity from number theory. Bézout's Identity states that for any two integers 'a' and 'b', there exist integers 'x' and 'y' such that ax + by = gcd(a, b), where gcd(a, b) is the greatest common divisor of 'a' and 'b'. Extending this, if we have a set of numbers, and their greatest common divisor is 1, then we can always find integer coefficients to form a linear combination that equals 1.

The Core Idea:

The problem asks whether we can obtain a sum of 1 using a subset of the numbers in nums, each multiplied by an integer (positive or negative). This is possible if and only if the greatest common divisor (GCD) of all numbers in nums is 1. If the GCD is greater than 1, it means all numbers share a common factor, and no linear combination can result in 1.

Algorithm:

  1. Calculate GCD: Iterate through the nums array and compute the GCD of all elements using Euclid's algorithm (or a built-in GCD function).
  2. Check GCD: Return true if the GCD is 1; otherwise, return false.

Time Complexity Analysis:

  • GCD Calculation: Euclid's algorithm for finding the GCD of two numbers has a time complexity of O(log(min(a, b))), where 'a' and 'b' are the two numbers. Since we're calculating the GCD iteratively for the entire array, the overall time complexity for this step is O(n * log(m)), where 'n' is the length of nums and 'm' is the maximum value in nums. In practice, this is often observed to be close to O(n) because the GCD tends to decrease rapidly.

  • Checking GCD: This is a constant-time O(1) operation.

Therefore, the overall time complexity is dominated by the GCD calculation, which is approximately O(n log m) or practically often closer to O(n).

Space Complexity Analysis:

The algorithm uses a constant amount of extra space to store variables like the current GCD. Therefore, the space complexity is O(1).

Code Implementation (Python, Java, C++, Go, TypeScript):

The code implementations below utilize Euclid's algorithm for GCD calculation. Some languages provide built-in GCD functions which can simplify the code slightly but won't change the complexity.

import math
 
def isGoodArray(nums):
    gcd_val = nums[0]
    for i in range(1, len(nums)):
        gcd_val = math.gcd(gcd_val, nums[i])  # Python's built-in GCD function
    return gcd_val == 1
 
class Solution {
    public boolean isGoodArray(int[] nums) {
        int gcd = nums[0];
        for (int i = 1; i < nums.length; i++) {
            gcd = gcd(gcd, nums[i]);
        }
        return gcd == 1;
    }
 
    private int gcd(int a, int b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }
}
#include <numeric> //for std::gcd
 
class Solution {
public:
    bool isGoodArray(vector<int>& nums) {
        int gcd = nums[0];
        for (int i = 1; i < nums.size(); ++i) {
            gcd = std::gcd(gcd, nums[i]); //C++'s built-in GCD function
        }
        return gcd == 1;
    }
};
func gcd(a, b int) int {
	if b == 0 {
		return a
	}
	return gcd(b, a%b)
}
 
func isGoodArray(nums []int) bool {
	result := nums[0]
	for i := 1; i < len(nums); i++ {
		result = gcd(result, nums[i])
	}
	return result == 1
}
function isGoodArray(nums: number[]): boolean {
    let gcd = nums[0];
    for (let i = 1; i < nums.length; i++) {
        gcd = gcd(gcd, nums[i]);
    }
    return gcd === 1;
}
 
function gcd(a: number, b: number): number {
    if (b === 0) return a;
    return gcd(b, a % b);
}

These code snippets all implement the same core algorithm with minor syntactic differences between languages. They all achieve the O(n log m) or practically O(n) time complexity and O(1) space complexity.