Minimize Length of Array Using Operations solution and explanation
9 more videos on this problem
3012. Minimize Length of Array Using Operations | Cases Problem | TrickyAryan Mittal · 20:03 · 3K views
3012 Minimize Length of Array Using Operations || Sorting + GCD ✅Ayush Rao · 8:44 · 985 views
3012. Minimize Length of Array Using Operations (Leetcode Medium)Programming Live with Larry · 29:01 · 478 views
3012. Minimize Length of Array Using Operations || Leetcode Biweekly Contest 122Ashish Kumar · 13:52 · 258 views
【每日一题】LeetCode 3012. Minimize Length of Array Using OperationsHuifeng Guan · 10:35 · 251 views
3012. Minimize Length of Array Using Operations | leetcode weekly contest 122 solution (in Hindi)Shivam Mishra LeetCode · 16:50 · 234 views
3012. Minimize Length of Array Using Operations | Greedy | BiWeekly 122Tech Courses · 10:33 · 223 views
100164. Minimize Length of Array Using Operations : LeetCode Biweekly Contest 122BitByBit - Learn Coding · 0:09 · 119 views
LeetCode Biweekly 122 - 3012 Minimize Length of Array Using Operations - MediumLearn with EmKay · 13:49 · 115 views
3012. Minimize Length of Array Using Operations | biweekly-contest-122Rohit Satpute · 10:11 · 89 views
The problem
You are given a 0-indexed integer array nums containing positive integers.
Your task is to minimize the length of nums by performing the following operations any number of times (including zero):
- Select two distinct indices
iandjfromnums, such thatnums[i] > 0andnums[j] > 0. - Insert the result of
nums[i] % nums[j]at the end ofnums. - Delete the elements at indices
iandjfromnums.
Return an integer denoting the minimum length of nums after performing the operation any number of times.
Example 1:
Input: nums = [1,4,3,1] Output: 1 Explanation: One way to minimize the length of the array is as follows: Operation 1: Select indices 2 and 1, insert nums[2] % nums[1] at the end and it becomes [1,4,3,1,3], then delete elements at indices 2 and 1. nums becomes [1,1,3]. Operation 2: Select indices 1 and 2, insert nums[1] % nums[2] at the end and it becomes [1,1,3,1], then delete elements at indices 1 and 2. nums becomes [1,1]. Operation 3: Select indices 1 and 0, insert nums[1] % nums[0] at the end and it becomes [1,1,0], then delete elements at indices 1 and 0. nums becomes [0]. The length of nums cannot be reduced further. Hence, the answer is 1. It can be shown that 1 is the minimum achievable length.
Example 2:
Input: nums = [5,5,5,10,5] Output: 2 Explanation: One way to minimize the length of the array is as follows: Operation 1: Select indices 0 and 3, insert nums[0] % nums[3] at the end and it becomes [5,5,5,10,5,5], then delete elements at indices 0 and 3. nums becomes [5,5,5,5]. Operation 2: Select indices 2 and 3, insert nums[2] % nums[3] at the end and it becomes [5,5,5,5,0], then delete elements at indices 2 and 3. nums becomes [5,5,0]. Operation 3: Select indices 0 and 1, insert nums[0] % nums[1] at the end and it becomes [5,5,0,0], then delete elements at indices 0 and 1. nums becomes [0,0]. The length of nums cannot be reduced further. Hence, the answer is 2. It can be shown that 2 is the minimum achievable length.
Example 3:
Input: nums = [2,3,4] Output: 1 Explanation: One way to minimize the length of the array is as follows: Operation 1: Select indices 1 and 2, insert nums[1] % nums[2] at the end and it becomes [2,3,4,3], then delete elements at indices 1 and 2. nums becomes [2,3]. Operation 2: Select indices 1 and 0, insert nums[1] % nums[0] at the end and it becomes [2,3,1], then delete elements at indices 1 and 0. nums becomes [1]. The length of nums cannot be reduced further. Hence, the answer is 1. It can be shown that 1 is the minimum achievable length.
Constraints:
1 <= nums.length <= 1051 <= nums[i] <= 109
Approach overview
Problem Overview: You are given an array of positive integers. In one operation, you choose two elements and replace the larger one with the remainder of dividing it by the smaller value. The goal is to apply operations so that the final array length becomes as small as possible.
Approach 1: Use Hashing for Efficient Search (O(n) time, O(n) space)
The key observation comes from number theory. Let m be the minimum value in the array. Any operation involving m turns another number x into x % m. If there exists an element where x % m != 0, that remainder will be smaller than m, creating a new minimum and allowing further reductions until the array collapses to a single element. You scan the array once, track frequencies using a hash map, and check remainders against m. If every number is divisible by m, the only elements that remain relevant are those equal to m. The minimal length becomes ceil(count(m) / 2) because pairs of minimum values can eliminate each other through operations.
This approach relies on fast frequency lookup and a single pass through the array. It fits naturally with problems involving arrays and remainder properties.
Approach 2: Two Pointers Technique (O(n log n) time, O(1) extra space)
Another way to reason about the process is to sort the array and simulate reductions using a greedy strategy. After sorting, the smallest value sits at the beginning. Use two pointers to examine how the minimum interacts with the rest of the array. If a value produces a non-zero remainder with the minimum, that remainder becomes a new smallest value and the array can ultimately shrink to length 1. If all numbers are multiples of the minimum, only elements equal to the minimum matter for the final state. By grouping identical minimum values and pairing them greedily, you end up with ceil(count(m)/2) remaining elements.
This method emphasizes the greedy structure of the operations and is helpful if you prefer reasoning through sorted order and pointer movement. It also connects with common interview patterns using greedy algorithms.
Recommended for interviews: The hashing approach is typically the expected optimal solution because it derives the mathematical insight quickly and runs in O(n) time. Walking through the brute reasoning about modulo behavior demonstrates understanding, while identifying the minimum-element property and reducing the problem to counting shows strong algorithmic intuition.
Approach 1: Approach 1: Use Hashing for Efficient Search
This approach leverages a hash table (or dictionary) to efficiently keep track of elements. The main idea is to iterate through the list of numbers, check if the complement (based on the target value) exists in the hash table, and if not, add the current number to the hash table.
By using a hash table, we can achieve average O(1) time complexity for insertion and lookup operations.
def two_sum(nums, target):
num_map = {}
for i, num in enumerate(nums):
complement = target - num
if complement in num_map:
return [num_map[complement], i]
num_map[num] = i
result = two_sum([2, 7, 11, 15], 9)
print("Indices:", result[0], result[1])import java.util.HashMap;
public class TwoSum {
public static int[] twoSum(int[] nums, int target) {
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
return new int[]{map.get(complement), i};
}
map.put(nums[i], i);
}
return new int[]{};
}
public static void main(String[] args) {
int[] nums = {2, 7, 11, 15};
int target = 9;
int[] result = twoSum(nums, target);
System.out.println("Indices: " + result[0] + ", " + result[1]);
}
}#include <iostream>
#include <unordered_map>
#include <vector>
std::vector<int> twoSum(std::vector<int>& nums, int target) {
std::unordered_map<int, int> map;
for (int i = 0; i < nums.size(); i++) {
int complement = target - nums[i];
if (map.find(complement) != map.end()) {
return {map[complement], i};
}
map[nums[i]] = i;
}
return {};
}
int main() {
std::vector<int> nums = {2, 7, 11, 15};
int target = 9;
std::vector<int> result = twoSum(nums, target);
std::cout << "Indices: " << result[0] << ", " << result[1] << std::endl;
return 0;
}function twoSum(nums, target) {
let map = new Map();
for (let i = 0; i < nums.length; i++) {
let complement = target - nums[i];
if (map.has(complement)) {
return [map.get(complement), i];
}
map.set(nums[i], i);
}
return [];
}
let result = twoSum([2, 7, 11, 15], 9);
console.log("Indices:", result[0], result[1]);#include <stdio.h>
#include <stdlib.h>
#define HASH_SIZE 1000
typedef struct Node {
int key;
int value;
struct Node* next;
} Node;
int hash_function(int key) {
return abs(key) % HASH_SIZE;
}
void insert(Node** hash_table, int key, int value) {
int hash_index = hash_function(key);
Node* new_node = (Node*)malloc(sizeof(Node));
new_node->key = key;
new_node->value = value;
new_node->next = hash_table[hash_index];
hash_table[hash_index] = new_node;
}
int find(Node** hash_table, int key) {
int hash_index = hash_function(key);
Node* node = hash_table[hash_index];
while (node) {
if (node->key == key) {
return node->value;
}
node = node->next;
}
return -1; // not found
}
void twoSum(int* nums, int numsSize, int target, int* returnSize) {
Node* hash_table[HASH_SIZE] = {NULL};
for (int i = 0; i < numsSize; i++) {
int complement = target - nums[i];
int index = find(hash_table, complement);
if (index != -1) {
returnSize[0] = index;
returnSize[1] = i;
return;
}
insert(hash_table, nums[i], i);
}
}
int main() {
int nums[] = {2, 7, 11, 15};
int target = 9;
int returnSize[2];
twoSum(nums, 4, target, returnSize);
printf("Indices: %d, %d\n", returnSize[0], returnSize[1]);
return 0;
}using System;
using System.Collections.Generic;
class TwoSumSolution {
public static int[] TwoSum(int[] nums, int target) {
Dictionary<int, int> map = new Dictionary<int, int>();
for (int i = 0; i < nums.Length; i++) {
int complement = target - nums[i];
if (map.ContainsKey(complement)) {
return new int[] { map[complement], i };
}
map[nums[i]] = i;
}
return new int[0];
}
static void Main() {
int[] nums = {2, 7, 11, 15};
int target = 9;
int[] result = TwoSum(nums, target);
Console.WriteLine("Indices: {0}, {1}", result[0], result[1]);
}
}This Python solution employs a dictionary to map each number to its index. For each iteration, it checks if the complement is in the dictionary. If found, the solution is returned; otherwise, the number is added to the dictionary with its index.
Time Complexity: O(n) since dictionary operations provide average O(1) time complexity, and O(n) for space due to storing elements in the dictionary.
Approach 2: Approach 2: Two Pointers Technique
This approach involves sorting the array and then using two pointers to efficiently find the two indices that sum up to the target. Begin by sorting the array; then initialize two pointers, one at the beginning ('left') and the other at the end ('right') of the sorted array. Adjust the pointers based on their sum until the target is found.
Note: This method entails returning indices of the values that sum up to the target rather than sorted positions.
def two_sum(nums, target):
num_index = [(num, i) for i, num in enumerate(nums)]
num_index.sort()
left, right = 0, len(nums) - 1
while left < right:
sum = num_index[left][0] + num_index[right][0]
if sum == target:
return [num_index[left][1], num_index[right][1]]
elif sum < target:
left += 1
else:
right -= 1
result = two_sum([2, 7, 11, 15], 9)
print("Indices:", result[0], result[1])import java.util.Arrays;
public class TwoSumIndices {
public static int[] twoSum(int[] nums, int target) {
int[][] numIndex = new int[nums.length][2];
for (int i = 0; i < nums.length; i++) {
numIndex[i][0] = nums[i];
numIndex[i][1] = i;
}
Arrays.sort(numIndex, (a, b) -> Integer.compare(a[0], b[0]));
int left = 0, right = nums.length - 1;
while (left < right) {
int sum = numIndex[left][0] + numIndex[right][0];
if (sum == target) {
return new int[]{numIndex[left][1], numIndex[right][1]};
} else if (sum < target) {
left++;
} else {
right--;
}
}
return new int[]{};
}
public static void main(String[] args) {
int[] nums = {2, 7, 11, 15};
int target = 9;
int[] result = twoSum(nums, target);
System.out.println("Indices: " + result[0] + ", " + result[1]);
}
}#include <iostream>
#include <vector>
#include <algorithm>
std::vector<int> twoSum(std::vector<int>& nums, int target) {
std::vector<std::pair<int, int>> num_index;
for (int i = 0; i < nums.size(); i++) {
num_index.push_back({nums[i], i});
}
std::sort(num_index.begin(), num_index.end());
int left = 0, right = nums.size() - 1;
while (left < right) {
int sum = num_index[left].first + num_index[right].first;
if (sum == target) {
return {num_index[left].second, num_index[right].second};
}
else if (sum < target) {
left++;
} else {
right--;
}
}
return {};
}
int main() {
std::vector<int> nums = {2, 7, 11, 15};
int target = 9;
std::vector<int> result = twoSum(nums, target);
std::cout << "Indices: " << result[0] << ", " << result[1] << std::endl;
return 0;
}function twoSum(nums, target) {
let numIndex = nums.map((num, index) => [num, index]);
numIndex.sort((a, b) => a[0] - b[0]);
let left = 0, right = nums.length - 1;
while (left < right) {
let sum = numIndex[left][0] + numIndex[right][0];
if (sum === target) {
return [numIndex[left][1], numIndex[right][1]];
} else if (sum < target) {
left++;
} else {
right--;
}
}
return [];
}
let result = twoSum([2, 7, 11, 15], 9);
console.log("Indices:", result[0], result[1]);#include <stdio.h>
#include <stdlib.h>
int cmp(const void* a, const void* b) {
return (*(int*)a - *(int*)b);
}
void twoSum(int* nums, int numsSize, int target, int* returnSize) {
int* original = (int*)malloc(numsSize * sizeof(int));
for (int i = 0; i < numsSize; i++) {
original[i] = nums[i];
}
qsort(nums, numsSize, sizeof(int), cmp);
int left = 0, right = numsSize - 1;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum == target) {
break;
} else if (sum < target) {
left++;
} else {
right--;
}
}
for (int i = 0; i < numsSize; i++) {
if (original[i] == nums[left] || original[i] == nums[right]) {
if (returnSize[0] == -1) {
returnSize[0] = i;
} else {
returnSize[1] = i;
break;
}
}
}
free(original);
}
int main() {
int nums[] = {2, 7, 11, 15};
int target = 9;
int returnSize[2] = {-1, -1};
twoSum(nums, 4, target, returnSize);
printf("Indices: %d, %d\n", returnSize[0], returnSize[1]);
return 0;
}using System;
using System.Collections.Generic;
class TwoSumSolution {
public static int[] TwoSum(int[] nums, int target) {
List<Tuple<int, int>> numIndex = new List<Tuple<int, int>>();
for (int i = 0; i < nums.Length; i++) {
numIndex.Add(new Tuple<int, int>(nums[i], i));
}
numIndex.Sort((a, b) => a.Item1.CompareTo(b.Item1));
int left = 0, right = nums.Length - 1;
while (left < right) {
int sum = numIndex[left].Item1 + numIndex[right].Item1;
if (sum == target) {
return new int[] { numIndex[left].Item2, numIndex[right].Item2 };
}
else if (sum < target) {
left++;
} else {
right--;
}
}
return new int[0];
}
static void Main() {
int[] nums = {2, 7, 11, 15};
int target = 9;
int[] result = TwoSum(nums, target);
Console.WriteLine("Indices: {0}, {1}", result[0], result[1]);
}
}The Python solution employs a list of tuples to track each element with its original index. The list is sorted, and the two-pointer technique is employed to find the pair of indices corresponding to the target sum, returned according to the original indices.
Time Complexity: O(n log n) for sorting; O(n) additional space for storing tuples.
Approach 3: Case Discussion
Let's denote the smallest element in the array nums as mi.
If mi appears only once, we can perform operations with mi and the other elements in the array nums to eliminate all other elements, leaving only mi. The answer is 1.
If mi appears multiple times, we need to check whether all elements in the array nums are multiples of mi. If not, there exists at least one element x such that 0 < x bmod mi < mi. This means we can construct an element smaller than mi through operations. This smaller element can eliminate all other elements through operations, leaving only this smaller element. The answer is 1. If all elements are multiples of mi, we can first use mi to eliminate all elements larger than mi. The remaining elements are all mi, with a count of cnt. Pair them up, and perform an operation for each pair. Finally, there will be \lceil cnt / 2 \rceil elements left, so the answer is \lceil cnt / 2 \rceil.
The time complexity is O(n), where n is the length of the array nums. The space complexity is O(1).
function minimumArrayLength(nums: number[]): number {
const mi = Math.min(...nums);
let cnt = 0;
for (const x of nums) {
if (x % mi) {
return 1;
}
if (x === mi) {
++cnt;
}
}
return (cnt + 1) >> 1;
}func minimumArrayLength(nums []int) int {
mi := slices.Min(nums)
cnt := 0
for _, x := range nums {
if x%mi != 0 {
return 1
}
if x == mi {
cnt++
}
}
return (cnt + 1) / 2
}Complexity comparison
| Approach | Complexity |
|---|---|
| Approach 1: Use Hashing for Efficient Search | Time Complexity: O(n) since dictionary operations provide average O(1) time complexity, and O(n) for space due to storing elements in the dictionary. |
| Approach 2: Two Pointers Technique | Time Complexity: O(n log n) for sorting; O(n) additional space for storing tuples. |
| Case Discussion | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Hashing with Minimum Element Insight | O(n) | O(n) | General case; fastest solution when scanning array once and tracking frequencies |
| Two Pointers After Sorting | O(n log n) | O(1) | Useful when sorting is acceptable and you want to reason about reductions using ordered elements |
Frequently asked questions
Is Minimize Length of Array Using Operations easy or hard?
The problem is rated Medium because the implementation is simple but the key insight is mathematical. Recognizing that the smallest element controls all modulo reductions and determines the final array length requires a number theory observation rather than brute simulation.
Minimize Length of Array Using Operations Python/Java solution
In Python or Java, compute the minimum value, count how many times it appears, and check if any element produces a non-zero remainder when divided by that minimum. If such an element exists return 1; otherwise return (countMin + 1) // 2. The implementation runs in linear time and uses simple loops and condition checks.
How to solve Minimize Length of Array Using Operations in O(n)?
Scan the array once to find the minimum value m and count its frequency. While scanning, check if any element x has x % m != 0. If such an element exists, the answer is 1 because a smaller remainder can be generated and propagate through operations. If all elements are divisible by m, the result becomes ceil(count(m)/2).
What is the best approach for Minimize Length of Array Using Operations?
The optimal approach uses a greedy number theory observation based on the minimum element in the array. If any number produces a non-zero remainder when divided by the minimum value, the array can eventually reduce to length 1. Otherwise, all numbers are multiples of the minimum and the result depends only on how many times the minimum appears, giving ceil(count(min)/2). This runs in O(n) time.
Is Minimize Length of Array Using Operations asked at Google/Amazon/Meta?
Problems involving modulo reductions, greedy observations, and minimum-element invariants commonly appear in interviews at companies like Google, Amazon, and Meta. Variants focusing on number theory insights and array transformations are frequently used to test mathematical reasoning in algorithm design.
What data structure is used in Minimize Length of Array Using Operations?
The primary data structures are arrays and a hash map (or frequency counter). The array is scanned to determine the minimum element and remainder behavior, while hashing helps track how many times the minimum value appears.
What is the time complexity of Minimize Length of Array Using Operations?
The optimal solution runs in O(n) time and O(n) space when using hashing to count frequencies and check divisibility against the minimum element. A sorting-based variant using two pointers runs in O(n log n) time due to the sorting step and uses O(1) additional space.
