1250. Check If It Is a Good Array
Problem Description
The problem presents us with an array of positive integers called nums
. Our goal is to check if it's possible to select a subset of these numbers, multiply each selected number by an integer, and then sum them up to get a total of 1. If this is possible, the array is considered "good". Otherwise, it is not good. The task is to determine if the given array is good or not, and we are to return True
if it is good and False
if it is not.
Intuition
To determine if an array is good or not, we can use a mathematical concept called the Greatest Common Divisor (GCD). The GCD of two numbers is the largest number that divides both of them without leaving a remainder. If we can extend this concept to find the GCD of all numbers in the array and the result is 1, this implies that we can form the number 1 as a linear combination of the array numbers, using the Bezout's identity theorem.
This means that if the GCD of the entire array is 1, there must be some subset of numbers in the array which can be multiplied by some integers to sum up to 1, since 1 is the only number that when used in linear combinations can produce any integer (and specifically the integer 1 in our case).
The Python code makes use of the reduce
function and the gcd
function from the [math](/problems/math-basics)
module. The reduce
function is used to apply the gcd
function cumulatively to the items of nums
, from left to right, so that we are effectively finding the GCD of all the numbers in the array. If the GCD turns out to be 1, the function returns True
. Otherwise, it returns False
. This simple approach elegantly checks if the array is good using built-in functions to perform the necessary calculations.
Learn more about Math patterns.
Solution Approach
The solution to this problem leverages the mathematical property of the Greatest Common Divisor (GCD) and a functional programming construct in Python.
Here's the step-by-step breakdown of the implementation:
-
Step 1: Import the
gcd
function from the[math](/problems/math-basics)
module.gcd
takes two numbers as arguments and returns their greatest common divisor. -
Step 2: Use the
reduce
function from thefunctools
module. Thereduce
function is a tool for performing a cumulative operation over an iterable. In this case, it applies thegcd
function starting with the first two elements of thenums
array, and then consecutively using the result as the first argument and the next element in the array as the second argument. -
Step 3: The
reduce
function will apply thegcd
function progressively across all elements of the array. Essentially, this means it will calculate thegcd
of the first and second elements, then take that result and calculate thegcd
with the third element, and so on until it processes the entire array. -
Step 4: After
reduce
has processed all the elements, we evaluate whether the accumulated GCD is1
. If the result is1
, it signifies that there is some combination of the array elements along with respective multiplicands that could add up to1
(thanks to Bezout's identity). If not, it implies that no such combination is possible. -
Step 5: The
isGoodArray
method returnsTrue
if the GCD is1
, signaling that the array is “good”, or returnsFalse
otherwise.
The algorithm relies on the following data structures and patterns:
- Arrays: The given input is an array that the algorithm iterates through.
- Functional Programming: Using
reduce
is an example of functional programming, as it applies a function cumulatively to the items of an iterable in a non-mutable way.
And that's it. By efficiently applying the gcd
function cumulatively across all elements in the nums
array, we can ascertain whether the array is "good" with a single line of code after the necessary functions are imported:
class Solution:
def isGoodArray(self, nums: List[int]) -> bool:
return reduce(gcd, nums) == 1
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's illustrate the solution approach with a small example. Suppose we are given the following array of positive integers:
nums = [6, 10, 15]
Now, let's walk through the process step by step:
-
Step 1: We first import the
gcd
function from themath
module, which will allow us to calculate the greatest common divisor of two given numbers. -
Step 2: We use the
reduce
function from thefunctools
module to apply thegcd
function cumulatively to the numbers in our arraynums
. -
Step 3: First,
reduce
applies thegcd
function to the first two elements, which are6
and10
. Thegcd
of6
and10
is2
. -
Step 4: The result (
2
) is then used with the next element in the array, which is15
. Thegcd
of2
and15
is1
. -
Step 5: Since the
reduce
function has finished processing all elements, we check if the accumulated GCD is1
. In our case, it is indeed1
.
According to Bezout's identity, because the final GCD is 1
, there must be a combination of integer multiples of some or all numbers in our array nums
that can add up to 1
. Hence, for our input array, the function isGoodArray
would evaluate to True
, indicating that the array is "good".
Here's a glimpse of how the code operates in this scenario:
from functools import reduce from math import gcd nums = [6, 10, 15] result = reduce(gcd, nums) is_good = result == 1 # This would be True in this case
The simplicity of this algorithm lies in its use of the gcd
function to examine the entire array in a single sweep. If the gcd of all elements is 1
, we can confidently say that the array is "good" as it meets the criteria outlined in the problem description.
Solution Implementation
1from functools import reduce
2from math import gcd
3
4class Solution:
5 def isGoodArray(self, nums: List[int]) -> bool:
6 # The function uses the greatest common divisor (gcd) to check if the array is 'good'.
7 # An array is 'good' if the gcd of all numbers in the array is 1.
8
9 # Use the reduce function to apply the gcd function cumulatively to the items of 'nums',
10 # from left to right, which reduces the array to a single value.
11 # Then, check if the final gcd value is 1.
12 return reduce(gcd, nums) == 1
13
1class Solution {
2
3 // Method to check if the array is a good array based on the condition.
4 // An array is considered good if the Greatest Common Divisor (GCD) of all its elements is 1.
5 public boolean isGoodArray(int[] nums) {
6 int gcdValue = 0; // Initialize the gcd value to 0.
7 // Iterate over each element in the array to find the overall gcd.
8 for (int num : nums) {
9 gcdValue = gcd(num, gcdValue); // Update gcdValue using the current element and the accumulated gcd.
10 if (gcdValue == 1) {
11 // If at any point the gcd becomes 1, we can return true immediately.
12 return true;
13 }
14 }
15 // The array is good if the final gcd value is 1.
16 return gcdValue == 1;
17 }
18
19 // Helper method to calculate the gcd of two numbers using Euclid's algorithm.
20 private int gcd(int a, int b) {
21 if (b == 0) {
22 // If the second number b is 0, then gcd is the first number a.
23 return a;
24 } else {
25 // Recursively call gcd with the second number and the remainder of a divided by b.
26 return gcd(b, a % b);
27 }
28 }
29}
30
1#include <vector>
2#include <numeric> // Required for std::gcd
3
4class Solution {
5public:
6 // Function to determine if the array is a "good" array.
7 // A "good" array is defined as an array where the greatest
8 // common divisor of all its elements is 1.
9 bool isGoodArray(std::vector<int>& nums) {
10 int greatestCommonDivisor = 0; // Initialize to 0
11 // Iterating through each element in the given array 'nums'.
12 for (int number : nums) {
13 // Update the greatest common divisor using std::gcd,
14 // which is in the numeric header.
15 greatestCommonDivisor = std::gcd(number, greatestCommonDivisor);
16 }
17 // The array is "good" if the GCD is 1 after processing all elements.
18 return greatestCommonDivisor == 1;
19 }
20};
21
1// Importing gcd function from a math utilities module
2// Note: TypeScript does not have a gcd function built-in, so you'll need to
3// either implement it yourself or include a library that provides it.
4
5function gcd(a: number, b: number): number {
6 // Base case for the recursion
7 if (b === 0) return a;
8 // Recursively calling gcd with the remainder
9 return gcd(b, a % b);
10}
11
12// Function to determine if the array is a "good" array.
13// A "good" array is defined as an array where the greatest
14// common divisor of all its elements is 1.
15function isGoodArray(nums: number[]): boolean {
16 let greatestCommonDivisor: number = 0; // Initialize to 0
17
18 // Iterating through each element in the given array 'nums'.
19 for (let number of nums) {
20 // Update the greatest common divisor using the gcd function.
21 greatestCommonDivisor = gcd(greatestCommonDivisor, number);
22 }
23
24 // The array is "good" if the GCD is 1 after processing all elements.
25 return greatestCommonDivisor === 1;
26}
27
Time and Space Complexity
Time Complexity
The time complexity of the function is determined by the reduce
function and the gcd
(greatest common divisor) operations it performs on the list elements.
- The
reduce
function applies thegcd
function cumulatively to the items of the list, from start to end, to reduce the list to a single value. - The
gcd
function runs inO(log(min(a, b)))
time, wherea
andb
are the numbers whose GCD is being calculated.
Assuming there are n
elements in the nums
list, the reduce
function will perform n-1
gcd operations. Due to the nature of GCD calculation, where after the first operation, the resulting GCD will often be lesser than or equal to the smallest number among the operands, each subsequent gcd
operation is typically faster than the last. However, for worst-case analysis, we'll consider each operation to have the complexity of O(log(k))
, where k
is the smallest element after each operation.
Therefore, the time complexity is:
O(n*log(k))
Where n
is the number of elements in the list and k
is the smallest number in the list at each step of the reduction.
Space Complexity
The space complexity of the code is O(1)
.
- This space complexity comes from the fact that the
gcd
operations do not require additional space that scales with the input size, as they are computed in constant space. - The
reduce
function does not create any new data structures that depend on the input size; it just iterates over the existing list and updates the accumulator in-place.
Thus, the space complexity is:
O(1)
Learn more about how to find time and space complexity quickly using problem constraints.
What does the following code do?
1def f(arr1, arr2):
2 i, j = 0, 0
3 new_arr = []
4 while i < len(arr1) and j < len(arr2):
5 if arr1[i] < arr2[j]:
6 new_arr.append(arr1[i])
7 i += 1
8 else:
9 new_arr.append(arr2[j])
10 j += 1
11 new_arr.extend(arr1[i:])
12 new_arr.extend(arr2[j:])
13 return new_arr
14
1public static List<Integer> f(int[] arr1, int[] arr2) {
2 int i = 0, j = 0;
3 List<Integer> newArr = new ArrayList<>();
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.add(arr1[i]);
8 i++;
9 } else {
10 newArr.add(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.add(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.add(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
1function f(arr1, arr2) {
2 let i = 0, j = 0;
3 let newArr = [];
4
5 while (i < arr1.length && j < arr2.length) {
6 if (arr1[i] < arr2[j]) {
7 newArr.push(arr1[i]);
8 i++;
9 } else {
10 newArr.push(arr2[j]);
11 j++;
12 }
13 }
14
15 while (i < arr1.length) {
16 newArr.push(arr1[i]);
17 i++;
18 }
19
20 while (j < arr2.length) {
21 newArr.push(arr2[j]);
22 j++;
23 }
24
25 return newArr;
26}
27
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!