Taro Logo

Minimum Operations to Make All Array Elements Equal

Medium
Asked by:
Profile picture
Profile picture
3 views
Topics:
ArraysBinary Search

You are given an array nums consisting of positive integers.

You are also given an integer array queries of size m. For the ith query, you want to make all of the elements of nums equal to queries[i]. You can perform the following operation on the array any number of times:

  • Increase or decrease an element of the array by 1.

Return an array answer of size m where answer[i] is the minimum number of operations to make all elements of nums equal to queries[i].

Note that after each query the array is reset to its original state.

Example 1:

Input: nums = [3,1,6,8], queries = [1,5]
Output: [14,10]
Explanation: For the first query we can do the following operations:
- Decrease nums[0] 2 times, so that nums = [1,1,6,8].
- Decrease nums[2] 5 times, so that nums = [1,1,1,8].
- Decrease nums[3] 7 times, so that nums = [1,1,1,1].
So the total number of operations for the first query is 2 + 5 + 7 = 14.
For the second query we can do the following operations:
- Increase nums[0] 2 times, so that nums = [5,1,6,8].
- Increase nums[1] 4 times, so that nums = [5,5,6,8].
- Decrease nums[2] 1 time, so that nums = [5,5,5,8].
- Decrease nums[3] 3 times, so that nums = [5,5,5,5].
So the total number of operations for the second query is 2 + 4 + 1 + 3 = 10.

Example 2:

Input: nums = [2,9,6,3], queries = [10]
Output: [20]
Explanation: We can increase each value in the array to 10. The total number of operations will be 8 + 1 + 4 + 7 = 20.

Constraints:

  • n == nums.length
  • m == queries.length
  • 1 <= n, m <= 105
  • 1 <= nums[i], queries[i] <= 109

Solution


Clarifying Questions

When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:

  1. What is the range of values for the integers within the input array?
  2. Can the input array be empty or null?
  3. If multiple elements appear most frequently, can I return the minimum number of operations required to make all elements equal to *any* one of the most frequent elements?
  4. Are the operations limited to only incrementing or decrementing array elements, or can I perform other operations?
  5. What data type should I use to represent the number of operations, considering potentially large arrays and value ranges?

Brute Force Solution

Approach

The brute-force method solves this by testing every possible number to see if it's the optimal target value. For each potential target value, we calculate the number of changes needed to make all other numbers equal to it. Finally, we select the target number requiring the fewest changes.

Here's how the algorithm would work step-by-step:

  1. Consider each distinct number from the input as a potential target value to which all other numbers will be made equal.
  2. For each potential target, go through the entire input and determine how many changes we'd have to make to turn all the numbers into the target value.
  3. Record the number of changes it took for each potential target.
  4. Once we've checked all potential targets, compare the number of changes each one required.
  5. The potential target that required the fewest changes is the answer, and the number of changes represents the minimum operations needed.

Code Implementation

def min_operations_brute_force(numbers):
    # Find potential targets by only using distinct array elements
    unique_numbers = set(numbers)
    minimum_operations = float('inf')

    for potential_target in unique_numbers:

        operations_count = 0
        # Count operations required for current target.

        for number in numbers:

            if number != potential_target:
                operations_count += 1

        # Determine if we have a new minimum

        minimum_operations = min(minimum_operations, operations_count)

    return minimum_operations

Big(O) Analysis

Time Complexity
O(n²)The algorithm iterates through each distinct number in the input array of size n as a potential target. For each target, it then iterates through the entire input array again to calculate the number of operations needed to convert each element to the target. This results in a nested loop structure where the outer loop iterates through at most n distinct elements and the inner loop iterates through n elements. Therefore, the time complexity is proportional to n * n, which simplifies to O(n²).
Space Complexity
O(K)The space complexity is determined by the number of distinct elements in the input array, where we are treating each distinct element as a potential target. The plain English explanation states we consider each distinct number from the input as a potential target value and record the number of changes for each. Therefore, we need to store a count for each distinct element. In the worst case, all N elements are distinct. But the plain english problem description implies we only store the number of changes for each distinct target (let K be the number of distinct values), not the targets themselves, leading to O(K) auxiliary space to store these counts. This auxiliary space scales with K, the number of distinct elements, and is independent of the original array's size N, although K can be at most N.

Optimal Solution

Approach

The most efficient way to solve this is to realize that all numbers must become equal to one particular value that already exists in the original set. We want to quickly figure out which of the existing values is the best 'target' and how many changes are needed to reach it.

Here's how the algorithm would work step-by-step:

  1. First, notice that the final equal value *must* be one of the numbers already in the set. Changing everything to a value that isn't there will always take more steps.
  2. Next, count how many times each unique number appears in the set. This tells us how many numbers would stay the same if we picked that number as our target.
  3. Now, find the number that appears most often. This is the number that requires the fewest changes to make everything else match it.
  4. Finally, the answer is the total number of numbers in the set minus the count of the most frequent number. This is because all the other numbers need to be changed.

Code Implementation

def minimum_operations_to_equal(numbers):
    frequency_of_numbers = {}
    for number in numbers:
        if number in frequency_of_numbers:
            frequency_of_numbers[number] += 1
        else:
            frequency_of_numbers[number] = 1

    # We need to find the most frequent number.
    most_frequent_number_count = 0
    for number in frequency_of_numbers:
        if frequency_of_numbers[number] > most_frequent_number_count:
            most_frequent_number_count = frequency_of_numbers[number]

    # The result is the total count minus the highest frequency.
    # This gives us the minimum operations needed.
    return len(numbers) - most_frequent_number_count

Big(O) Analysis

Time Complexity
O(n)The algorithm first counts the frequency of each number in the input array of size n, which takes O(n) time. Finding the number with the highest frequency also involves iterating through the frequency counts, taking at most O(n) time. The final subtraction to find the minimum operations is a constant time operation. Therefore, the overall time complexity is dominated by the initial frequency counting, resulting in O(n).
Space Complexity
O(N)The solution uses a dictionary (or hash map) to count the frequency of each unique number in the input array. In the worst-case scenario, all N numbers in the input array are unique, leading to N key-value pairs in the frequency counter. Therefore, the auxiliary space used by the dictionary grows linearly with the size of the input array. The space used to store variables like the count of the most frequent number is constant and does not affect the overall space complexity.

Edge Cases

CaseHow to Handle
Null input arrayThrow an IllegalArgumentException or return an empty list indicating invalid input.
Empty input arrayReturn 0 operations, since all elements are already 'equal' in an empty array.
Array with a single elementReturn 0 operations because a single element array is already equal.
All elements are already equalReturn 0 operations, as no changes are needed.
Array contains negative numbersThe core logic should handle negative numbers correctly, so no specific handling is required if the 'equal' condition still applies after the transformation.
Array contains zeroThe algorithm should handle zero values correctly without special treatment.
Integer overflow during intermediate calculations (e.g., sum or differences)Use long data types for intermediate calculations to prevent integer overflow issues, or choose an algorithm that avoids large intermediate values.
Large array size leading to potential memory issuesEnsure the algorithm's space complexity is reasonable (e.g., O(1) or O(log n)), or consider using an algorithm that processes the array in chunks if memory is a constraint.