2654. Minimum Number of Operations to Make All Array Elements Equal to 1
Problem Description
You have an array nums
of positive integers (0-indexed). You can perform the following operation any number of times:
- Choose any index
i
where0 <= i < n - 1
- Replace either
nums[i]
ornums[i+1]
with their greatest common divisor (GCD)
Your goal is to make all elements in the array equal to 1 using the minimum number of operations. If it's impossible to achieve this, return -1.
For example, if you have two adjacent elements like [6, 10]
, you could replace either the 6 or the 10 with their GCD which is 2, giving you either [2, 10]
or [6, 2]
.
The key insight is that you need to determine:
- Whether it's possible to reduce all elements to 1 (this is only possible if the GCD of all elements together equals 1)
- If possible, what's the minimum number of operations needed
The solution considers two main cases:
- If there are already some 1s in the array, you can use each 1 to convert its neighbors to 1 through GCD operations (since GCD(1, any number) = 1)
- If there are no 1s initially, you first need to create at least one 1 by finding the shortest subarray whose GCD equals 1, then spread that 1 to all other elements
The operation count depends on how many elements need to be changed and the minimum steps required to create the first 1 (if needed).
Intuition
The first observation is that once we have a single 1
in the array, we can propagate it to all other elements. This is because GCD(1, x) = 1
for any positive integer x
. So if we have a 1
at position i
, we can make position i+1
equal to 1
, then use that new 1
to convert position i+2
, and so on. Similarly, we can propagate leftward.
If the array already contains some 1
s, we don't need to create any. We just need to convert all non-1 elements to 1
. Each non-1 element requires exactly one operation to become 1
(by taking GCD with an adjacent 1
). So if we have cnt
ones already, we need n - cnt
operations.
The challenging case is when there are no 1
s initially. We need to create at least one 1
first. To create a 1
, we need to find two or more consecutive elements whose GCD equals 1
. The key insight is that we want to find the shortest such subarray because:
- Creating a
1
from a subarray of lengthk
requiresk - 1
operations (we repeatedly take GCD of adjacent pairs until we reduce the entire subarray to a single1
) - Once we have one
1
, we needn - 1
more operations to propagate it to all other positions
Therefore, we search for the minimum length subarray whose GCD is 1
. For each starting position i
, we extend to position j
and compute the GCD of elements from i
to j
. When this GCD becomes 1
, we've found a candidate subarray of length j - i + 1
.
If no such subarray exists (meaning the GCD of the entire array is greater than 1
), it's impossible to make all elements equal to 1
, so we return -1
.
The total operations needed when starting with no 1
s is: (minimum subarray length - 1)
to create the first 1
, plus (n - 1)
to propagate it to all positions.
Learn more about Math patterns.
Solution Approach
The implementation follows a two-phase approach based on whether 1
s already exist in the array:
Phase 1: Check for existing 1s
cnt = nums.count(1) if cnt: return n - cnt
First, we count how many 1
s are already in the array. If there are any 1
s present, we can immediately return n - cnt
since each non-1 element needs exactly one operation to become 1
through GCD with an adjacent 1
.
Phase 2: Find minimum length subarray with GCD = 1
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)
If no 1
s exist, we need to create one. We use a nested loop approach:
- The outer loop iterates through each starting position
i
- For each starting position, we progressively extend the subarray by including elements at position
j
- We maintain a running GCD
g
of all elements in the current subarray[i, j]
- The property
GCD(a, GCD(b, c)) = GCD(GCD(a, b), c)
allows us to update the GCD incrementally - When
g
becomes1
, we've found a valid subarray of lengthj - i + 1
- We track the minimum length found in variable
mi
Final calculation:
return -1 if mi > n else n - 1 + mi - 1
- If
mi > n
, no valid subarray was found (impossible case), return-1
- Otherwise, return
n - 1 + mi - 1
, which simplifies ton + mi - 2
:mi - 1
operations to create the first1
from the minimum length subarrayn - 1
operations to propagate this1
to all other positions
The algorithm has time complexity O(n² × log(max(nums)))
where the log factor comes from the GCD computation, and space complexity O(1)
as we only use a few variables.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with the array nums = [6, 10, 15]
.
Step 1: Check for existing 1s
- Count of 1s = 0
- Since there are no 1s, we need to create one first
Step 2: Find minimum length subarray with GCD = 1
We'll check all possible subarrays:
Starting at index 0:
- Subarray [6]: GCD = 6 (not 1)
- Subarray [6, 10]: GCD(6, 10) = 2 (not 1)
- Subarray [6, 10, 15]: GCD(GCD(6, 10), 15) = GCD(2, 15) = 1 ✓
- Length = 3
Starting at index 1:
- Subarray [10]: GCD = 10 (not 1)
- Subarray [10, 15]: GCD(10, 15) = 5 (not 1)
Starting at index 2:
- Subarray [15]: GCD = 15 (not 1)
Minimum subarray length found = 3
Step 3: Calculate total operations
To create the first 1 from the subarray [6, 10, 15]:
- Operation 1: Replace 6 with GCD(6, 10) = 2 → [2, 10, 15]
- Operation 2: Replace 2 with GCD(2, 15) = 1 → [1, 10, 15]
- This took
3 - 1 = 2
operations
Now propagate the 1 to remaining elements:
- Operation 3: Replace 10 with GCD(1, 10) = 1 → [1, 1, 15]
- Operation 4: Replace 15 with GCD(1, 15) = 1 → [1, 1, 1]
- This took
3 - 1 = 2
more operations
Total operations = (mi - 1) + (n - 1) = 2 + 2 = 4
Using the formula: n + mi - 2 = 3 + 3 - 2 = 4
✓
Solution Implementation
1from typing import List
2from math import gcd
3
4class Solution:
5 def minOperations(self, nums: List[int]) -> int:
6 """
7 Find minimum operations to make all elements equal to 1.
8 Each operation: replace two adjacent elements with their GCD.
9 """
10 n = len(nums)
11
12 # Count existing 1s in the array
13 ones_count = nums.count(1)
14
15 # If there are already 1s, we need (n - ones_count) operations
16 # to convert all non-1 elements to 1
17 if ones_count > 0:
18 return n - ones_count
19
20 # Find minimum length subarray with GCD = 1
21 min_length = n + 1
22
23 for start_idx in range(n):
24 current_gcd = 0
25
26 # Check all subarrays starting from start_idx
27 for end_idx in range(start_idx, n):
28 current_gcd = gcd(current_gcd, nums[end_idx])
29
30 # If we found a subarray with GCD = 1
31 if current_gcd == 1:
32 subarray_length = end_idx - start_idx + 1
33 min_length = min(min_length, subarray_length)
34 break # No need to extend this subarray further
35
36 # If no subarray has GCD = 1, it's impossible
37 if min_length > n:
38 return -1
39
40 # Operations needed: (min_length - 1) to create first 1,
41 # then (n - 1) to propagate it to all positions
42 return n - 1 + min_length - 1
43
1class Solution {
2 /**
3 * Finds the minimum number of operations to make all elements in the array equal to 1.
4 * An operation consists of replacing an element with the GCD of two adjacent elements.
5 *
6 * @param nums the input array
7 * @return minimum operations needed, or -1 if impossible
8 */
9 public int minOperations(int[] nums) {
10 int arrayLength = nums.length;
11
12 // Count how many 1s already exist in the array
13 int onesCount = 0;
14 for (int num : nums) {
15 if (num == 1) {
16 onesCount++;
17 }
18 }
19
20 // If there are already 1s in the array, we need (n - onesCount) operations
21 // to convert all non-1 elements to 1
22 if (onesCount > 0) {
23 return arrayLength - onesCount;
24 }
25
26 // Find the minimum length subarray whose GCD equals 1
27 int minSubarrayLength = arrayLength + 1;
28
29 // Try all possible subarrays starting from index i
30 for (int i = 0; i < arrayLength; i++) {
31 int currentGcd = 0;
32
33 // Extend the subarray from i to j
34 for (int j = i; j < arrayLength; j++) {
35 // Calculate GCD of all elements from index i to j
36 currentGcd = gcd(currentGcd, nums[j]);
37
38 // If we found a subarray with GCD = 1, update minimum length
39 if (currentGcd == 1) {
40 minSubarrayLength = Math.min(minSubarrayLength, j - i + 1);
41 break; // No need to extend further from this starting point
42 }
43 }
44 }
45
46 // If no subarray with GCD = 1 exists, return -1
47 if (minSubarrayLength > arrayLength) {
48 return -1;
49 }
50
51 // Total operations = (minSubarrayLength - 1) to create first 1
52 // + (arrayLength - 1) to propagate 1 to all positions
53 return arrayLength - 1 + minSubarrayLength - 1;
54 }
55
56 /**
57 * Calculates the Greatest Common Divisor (GCD) of two numbers using Euclidean algorithm.
58 *
59 * @param a first number
60 * @param b second number
61 * @return GCD of a and b
62 */
63 private int gcd(int a, int b) {
64 return b == 0 ? a : gcd(b, a % b);
65 }
66}
67
1class Solution {
2public:
3 int minOperations(vector<int>& nums) {
4 int n = nums.size();
5
6 // Count how many 1s already exist in the array
7 int onesCount = 0;
8 for (int num : nums) {
9 if (num == 1) {
10 ++onesCount;
11 }
12 }
13
14 // If there are already 1s in the array, we need (n - onesCount) operations
15 // to convert all other elements to 1
16 if (onesCount > 0) {
17 return n - onesCount;
18 }
19
20 // Find the minimum length subarray whose GCD is 1
21 int minLength = n + 1;
22 for (int i = 0; i < n; ++i) {
23 int currentGcd = 0;
24 for (int j = i; j < n; ++j) {
25 // Calculate GCD of subarray nums[i..j]
26 currentGcd = gcd(currentGcd, nums[j]);
27
28 // If GCD becomes 1, update minimum length
29 if (currentGcd == 1) {
30 minLength = min(minLength, j - i + 1);
31 break; // No need to extend this subarray further
32 }
33 }
34 }
35
36 // If no subarray has GCD of 1, it's impossible to create any 1s
37 if (minLength > n) {
38 return -1;
39 }
40
41 // Total operations: (minLength - 1) to create the first 1,
42 // then (n - 1) operations to convert all other elements to 1
43 return (minLength - 1) + (n - 1);
44 }
45};
46
1/**
2 * Calculates the minimum number of operations to make all elements in the array equal to 1
3 * An operation consists of replacing an element with the GCD of two adjacent elements
4 * @param nums - The input array of positive integers
5 * @returns The minimum number of operations, or -1 if impossible
6 */
7function minOperations(nums: number[]): number {
8 const arrayLength: number = nums.length;
9
10 // Count how many 1s are already in the array
11 let onesCount: number = 0;
12 for (const num of nums) {
13 if (num === 1) {
14 onesCount++;
15 }
16 }
17
18 // If there are already 1s in the array, we need (n - onesCount) operations
19 // to convert all other elements to 1
20 if (onesCount > 0) {
21 return arrayLength - onesCount;
22 }
23
24 // Find the minimum length subarray whose GCD equals 1
25 let minSubarrayLength: number = arrayLength + 1;
26
27 // Try all possible subarrays starting from index i
28 for (let startIndex: number = 0; startIndex < arrayLength; startIndex++) {
29 let currentGcd: number = 0;
30
31 // Extend the subarray from startIndex to endIndex
32 for (let endIndex: number = startIndex; endIndex < arrayLength; endIndex++) {
33 // Calculate GCD of current subarray
34 currentGcd = gcd(currentGcd, nums[endIndex]);
35
36 // If we found a subarray with GCD = 1, update minimum length
37 if (currentGcd === 1) {
38 minSubarrayLength = Math.min(minSubarrayLength, endIndex - startIndex + 1);
39 }
40 }
41 }
42
43 // If no subarray has GCD = 1, it's impossible to make all elements 1
44 if (minSubarrayLength > arrayLength) {
45 return -1;
46 }
47
48 // Total operations = (minSubarrayLength - 1) to create first 1
49 // + (arrayLength - 1) to propagate 1 to all positions
50 return arrayLength - 1 + minSubarrayLength - 1;
51}
52
53/**
54 * Calculates the Greatest Common Divisor (GCD) of two numbers using Euclidean algorithm
55 * @param a - First number
56 * @param b - Second number
57 * @returns The GCD of a and b
58 */
59function gcd(a: number, b: number): number {
60 return b === 0 ? a : gcd(b, a % b);
61}
62
Time and Space Complexity
Time Complexity: O(n²)
The algorithm consists of several parts:
- Counting 1s in the array takes
O(n)
time - If there are no 1s, we have nested loops:
- Outer loop runs
n
times (fromi = 0
ton-1
) - Inner loop runs at most
n-i
times for eachi
- Inside the inner loop,
gcd(g, nums[j])
operation takesO(log(max(nums)))
time - Since we're looking for the minimum subarray with GCD = 1, in the worst case we examine all
O(n²)
subarrays
- Outer loop runs
The total time complexity is O(n² × log(max(nums)))
. However, since the log factor is typically small compared to array operations and the problem constraints usually have bounded values, this is often simplified to O(n²)
.
Space Complexity: O(1)
The algorithm uses only a constant amount of extra space:
- Variables
n
,cnt
,mi
,i
,j
, andg
each takeO(1)
space - No additional data structures are created
- The
gcd
function usesO(1)
space (iterative implementation) orO(log(min(a,b)))
space if recursive, but this doesn't affect the overall complexity
Therefore, the space complexity is O(1)
excluding the input array.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrect GCD Initialization
A common mistake is initializing the GCD variable incorrectly when computing the GCD of a subarray. Some might initialize it as current_gcd = nums[start_idx]
instead of current_gcd = 0
.
Why it's wrong: Starting with nums[start_idx]
would skip including that element in the GCD calculation for the first iteration.
Correct approach: Initialize with 0 because GCD(0, x) = x
for any positive integer x, which correctly includes the first element.
# Wrong
for start_idx in range(n):
current_gcd = nums[start_idx] # Incorrect initialization
for end_idx in range(start_idx + 1, n): # Skips single element check
current_gcd = gcd(current_gcd, nums[end_idx])
# Correct
for start_idx in range(n):
current_gcd = 0 # Correct initialization
for end_idx in range(start_idx, n):
current_gcd = gcd(current_gcd, nums[end_idx])
2. Forgetting to Check Single Element Arrays
When the array has only one element, the logic needs special handling. If n = 1
and nums[0] = 1
, the answer is 0. If nums[0] ≠ 1
, it's impossible (-1).
Solution: The provided code handles this correctly through the initial check for existing 1s and the impossibility check, but it's easy to overlook in custom implementations.
3. Incorrect Final Operation Count
A frequent error is miscalculating the total operations needed when no 1s exist initially.
Common mistakes:
- Returning just
min_length - 1
(forgetting to propagate the 1) - Returning
n + min_length
(off by one error) - Returning
2 * (n - 1)
(assuming symmetric operations)
Correct formula: (min_length - 1) + (n - 1)
where:
min_length - 1
: operations to create the first 1 from the minimum subarrayn - 1
: operations to propagate that 1 to all other positions
4. Breaking Too Early in Subarray Search
Some might break immediately after finding the first subarray with GCD = 1, missing potentially shorter subarrays.
# Wrong - stops at first valid subarray
for i in range(n):
g = 0
for j in range(i, n):
g = gcd(g, nums[j])
if g == 1:
return n + (j - i + 1) - 2 # Wrong! Might not be minimum
# Correct - finds minimum length across all valid subarrays
min_length = n + 1
for i in range(n):
g = 0
for j in range(i, n):
g = gcd(g, nums[j])
if g == 1:
min_length = min(min_length, j - i + 1)
break # Can break here since extending won't give shorter subarray
5. Not Handling the Impossible Case
Forgetting that if the GCD of the entire array is greater than 1, it's impossible to make all elements equal to 1.
Example: For array [2, 4, 6, 8]
, the GCD of all elements is 2, so no sequence of operations can produce a 1.
Solution: The check if min_length > n: return -1
handles this case, as no valid subarray will be found if the overall GCD > 1.
In a binary min heap, the maximum element can be found in:
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
Coding Interview 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
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 assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!