Minimum Number of Operations to Make All Array Elements Equal to 1
MedPrompt
You are given a 0-indexed array nums consisiting of positive integers. You can do the following operation on the array any number of times:
- Select an index
isuch that0 <= i < n - 1and replace either ofnums[i]ornums[i+1]with their gcd value.
Return the minimum number of operations to make all elements of nums equal to 1. If it is impossible, return -1.
The gcd of two integers is the greatest common divisor of the two integers.
Example 1:
Input: nums = [2,6,3,4]
Output: 4
Explanation: We can do the following operations:
- Choose index i = 2 and replace nums[2] with gcd(3,4) = 1. Now we have nums = [2,6,1,4].
- Choose index i = 1 and replace nums[1] with gcd(6,1) = 1. Now we have nums = [2,1,1,4].
- Choose index i = 0 and replace nums[0] with gcd(2,1) = 1. Now we have nums = [1,1,1,4].
- Choose index i = 2 and replace nums[3] with gcd(1,4) = 1. Now we have nums = [1,1,1,1].Example 2:
Input: nums = [2,10,6,14]
Output: -1
Explanation: It can be shown that it is impossible to make all the elements equal to 1.
Constraints:
2 <= nums.length <= 501 <= nums[i] <= 106
Approaches
2 approaches with complexity analysis and trade-offs.
This approach systematically checks every possible contiguous subarray within the input array nums to find the shortest one whose elements have a greatest common divisor (GCD) of 1. The core idea is that to make all elements 1, we must first create a 1 if none exists. The minimum number of operations to create a 1 is k-1, where k is the length of the shortest subarray with a GCD of 1. Once a 1 is created, it takes an additional n-1 operations to make all other elements 1.
Algorithm
- Define a helper function
gcd(a, b)that computes the greatest common divisor of two integers. - Count the number of
1s in the input arraynums. Let this beones. - If
ones > 0, returnnums.length - ones. - Iterate through all possible subarray lengths
lenfrom 2 tonums.length. - For each
len, iterate through all possible start indicesifrom 0 tonums.length - len. - Calculate the GCD of the subarray
nums[i...i+len-1].- Initialize
currentGcd = nums[i]. - Iterate
jfromi+1toi+len-1. - Update
currentGcd = gcd(currentGcd, nums[j]).
- Initialize
- If
currentGcd == 1, we have found the shortest subarray. The length islen. The total operations are(len - 1) + (nums.length - 1). Return this value. - If the loops complete without finding a subarray with GCD 1, it's impossible. Return -1.
Walkthrough
First, we handle two edge cases:
- If the array already contains
1s, we don't need to create a1. We can use an existing1to turn its neighbors into1, and so on. The number of operations required is simply the number of elements that are not1. This isn - countOnes, wherenis the array length andcountOnesis the number of1s. - It's impossible to create a
1if the GCD of all elements in the initial array is greater than 1. This is because any number generated by thegcdoperation will be a multiple of the initial GCD. So, ifgcd(nums) > 1, we return -1.
If neither of these cases applies (i.e., no 1s exist, but it's possible to create one), we proceed to find the shortest subarray with a GCD of 1.
The algorithm is as follows:
- Count the number of
1s innums. If it's greater than zero, returnn - countOnes. - Initialize
minLengthto a very large value (orn+1). - Iterate through all possible subarray lengths,
len, from 2 ton. - For each
len, iterate through all possible starting indices,i, from 0 ton - len. - For each subarray
nums[i...i+len-1], calculate its GCD. - If the GCD is 1, we have found the shortest possible subarray because we are iterating
lenin increasing order. The length islen. We can setminLength = lenand break out of all loops. - If a
minLengthwas found, the total number of operations is(minLength - 1)(to create the first1) plus(n - 1)(to propagate the1to the othern-1elements). ReturnminLength - 1 + n - 1. - If the loops complete and no such subarray is found, it implies impossibility. This happens if the GCD of the entire array is greater than 1.
class Solution { private int gcd(int a, int b) { while (b != 0) { int temp = b; b = a % b; a = temp; } return a; } public int minOperations(int[] nums) { int n = nums.length; int ones = 0; for (int num : nums) { if (num == 1) { ones++; } } if (ones > 0) { return n - ones; } // Find shortest subarray with GCD of 1 for (int len = 2; len <= n; len++) { for (int i = 0; i <= n - len; i++) { int currentGcd = nums[i]; for (int j = i + 1; j < i + len; j++) { currentGcd = gcd(currentGcd, nums[j]); } if (currentGcd == 1) { // Found the shortest length, calculate result and return return (len - 1) + (n - 1); } } } // If no subarray has GCD of 1, it's impossible. return -1; }}Complexity
Time
O(n^3 * log(max_val)). The outer loop for `len` runs `n-1` times. The middle loop for `i` runs up to `n` times. The inner loop to calculate the GCD of a subarray of length `len` runs `len-1` times, and each `gcd` call takes `O(log(max_val))` time, where `max_val` is the maximum value in `nums`. This results in a total complexity dominated by the nested loops.
Space
O(1). We only use a few variables to store intermediate results.
Trade-offs
Pros
Conceptually straightforward, directly implementing the definition of finding the shortest subarray.
Correctly solves the problem.
Cons
Inefficient due to the triple nested loop structure. It recomputes the GCD for overlapping subarrays multiple times.
This approach improves upon the brute-force method by avoiding redundant GCD calculations. Instead of re-calculating the GCD for every subarray from scratch, we can compute it incrementally. For a fixed starting point i, we can find the GCD of nums[i...j] by using the already computed GCD of nums[i...j-1]. This optimization reduces the time complexity significantly.
Algorithm
- Define a helper function
gcd(a, b). - Count the number of
1s innums. Let this beones. - If
ones > 0, returnnums.length - ones. - Initialize
minLength = Integer.MAX_VALUE. - Iterate
ifrom 0 tonums.length - 1.- Initialize
currentGcd = nums[i]. - Iterate
jfromi + 1tonums.length - 1.- Update
currentGcd = gcd(currentGcd, nums[j]). - If
currentGcd == 1:- The length of this subarray is
j - i + 1. - Update
minLength = min(minLength, j - i + 1). - Break the inner loop (as we've found the shortest subarray starting at
i).
- The length of this subarray is
- Update
- Initialize
- If
minLengthis stillInteger.MAX_VALUE, it's impossible. Return -1. - Otherwise, return
(minLength - 1) + (nums.length - 1).
Walkthrough
The overall logic remains the same: handle the case with existing 1s and the impossible case first. The improvement lies in how we find the shortest subarray with a GCD of 1 when no 1s are initially present.
The algorithm is as follows:
- Count the number of
1s innums. IfcountOnes > 0, returnn - countOnes. - Initialize
minLengthto a very large value. - Iterate through the array with an outer loop for the start index
ifrom 0 ton-1. - For each
i, start a running GCD calculation. InitializecurrentGcd = nums[i]. - Use an inner loop for the end index
jfromi+1ton-1. - In the inner loop, update the running GCD:
currentGcd = gcd(currentGcd, nums[j]). - If at any point
currentGcdbecomes 1, it means the subarraynums[i...j]has a GCD of 1. The length of this subarray isj - i + 1. - We update our
minLengthwithmin(minLength, j - i + 1). Since we are looking for the shortest subarray starting ati, we canbreakthe inner loop once we find a1and move to the next starting indexi+1. - After checking all possible starting positions
i, ifminLengthis still at its initial large value, it means no subarray has a GCD of 1. In this scenario, it's impossible to make all elements 1, so we return -1. - Otherwise, the minimum operations needed is
(minLength - 1)(to create the first1) plus(n - 1)(to make the other elements1). ReturnminLength - 1 + n - 1.
class Solution { private int gcd(int a, int b) { while (b != 0) { int temp = b; b = a % b; a = temp; } return a; } public int minOperations(int[] nums) { int n = nums.length; int ones = 0; for (int num : nums) { if (num == 1) { ones++; } } if (ones > 0) { return n - ones; } int minLength = Integer.MAX_VALUE; for (int i = 0; i < n; i++) { int currentGcd = nums[i]; for (int j = i + 1; j < n; j++) { currentGcd = gcd(currentGcd, nums[j]); if (currentGcd == 1) { minLength = Math.min(minLength, j - i + 1); break; // Found shortest subarray starting at i } } } if (minLength == Integer.MAX_VALUE) { return -1; // Impossible to make a 1 } return (minLength - 1) + (n - 1); }}Complexity
Time
O(n^2 * log(max_val)). The check for `1`s takes `O(n)`. The nested loops for finding the minimum length subarray run in `O(n^2)`. Inside the inner loop, we perform one `gcd` operation, which takes `O(log(max_val))`. The total time complexity is dominated by the nested loops.
Space
O(1). We only use a constant amount of extra space for variables.
Trade-offs
Pros
Efficient for the given constraints (
n <= 50).Correctly handles all cases.
Improves upon the brute-force approach by eliminating redundant computations.
Cons
The core logic still relies on checking subarrays, which has a quadratic time complexity. For much larger
n, this might be too slow.
Solutions
Solution
class Solution {public int minOperations(int[] nums) { int n = nums.length; int cnt = 0; for (int x : nums) { if (x == 1) { ++cnt; } } if (cnt > 0) { return n - cnt; } int mi = n + 1; for (int i = 0; i < n; ++i) { int g = 0; for (int j = i; j < n; ++j) { g = gcd(g, nums[j]); if (g == 1) { mi = Math.min(mi, j - i + 1); } } } return mi > n ? -1 : n - 1 + mi - 1; }private int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }}class Solution {public: int minOperations(vector<int> &nums) { int n = nums.size(); int cnt = 0; for (int x : nums) { if (x == 1) { ++cnt; } } if (cnt) { return n - cnt; } int mi = n + 1; for (int i = 0; i < n; ++i) { int g = 0; for (int j = i; j < n; ++j) { g = gcd(g, nums[j]); if (g == 1) { mi = min(mi, j - i + 1); } } } return mi > n ? -1 : n - 1 + mi - 1; }};class Solution: def minOperations(self, nums: List[int]) -> int: n = len(nums) cnt = nums . count(1) if cnt: return n - cnt mi = n + 1 for i in range(n): g = 0 for j in range(i, n): g = gcd(g, nums[j]) if g == 1: mi = min(mi, j - i + 1) return - 1 if mi > n else n - 1 + mi - 1Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.