Minimize Deviation in Array

Updated on 16 June, 2025
Minimize Deviation in Array header image

Problem Statement

You are provided with an array nums consisting of n positive integers. The array has the flexibility whereby each element can be manipulated through certain operations indefinitely. The operations are based on the parity of the element:

  • If the element is even, you can reduce its value by dividing it by 2.
  • If the element is odd, you can increase its value by multiplying it by 2.

The goal of these operations is to minimize the deviation in the array, where deviation is defined as the maximum difference between any two elements in the array. The task is to compute the minimum possible deviation that can be achieved after applying any number, including zero, of the allowed operations.

Examples

Example 1

Input:

nums = [1,2,3,4]

Output:

1

Explanation:

You can transform the array to [1,2,3,2], then to [2,2,3,2], then the deviation will be 3 - 2 = 1.

Example 2

Input:

nums = [4,1,5,20,3]

Output:

3

Explanation:

You can transform the array after two operations to [4,2,5,5,3], then the deviation will be 5 - 2 = 3.

Example 3

Input:

nums = [2,10,8]

Output:

3

Constraints

  • n == nums.length
  • 2 <= n <= 5 * 104
  • 1 <= nums[i] <= 109

Approach and Intuition

To solve the problem of minimizing the deviation of the array after performing operations on its elements, consider the following insights and approach:

  1. Initial Transformation:

    • For all elements that are odd, perform the multiplication operation to make them even. This step is crucial because:
      • Multiplying an odd number by 2 gives an even number.
      • Even numbers can be reduced (by dividing by 2 multiple times) until they become odd, providing flexibility in adjustment.
  2. Sort and Use Priority Queue:

    • Employ a priority queue (max heap) to keep track of numbers, where you always have access to the maximum number.
    • Bring numbers in the max heap down to possibly their lowest value by repeatedly dividing the largest numbers until it becomes odd.
  3. Tracking Minimum Deviation:

    • Since every number is reduced to its bare minimum value or to a value where reducing it further will make it odd, the difference between the smallest number and the largest number in this transformed array will be a point of interest.
    • Each iteration through the priority queue, update if the current maximum and minimum provide a smaller deviation than previously recorded.
  4. Max Heap Operations:

    • Given you initially form all numbers to even, start reducing from the largest while keeping track of minimum numbers. By ensuring the current max is pushed down (divided by 2), and adding this to the max heap, the difference between current max and minimum is checked against the smallest deviation found so far.
  5. Complexity and Feasibility:

    • Since each number in the worst case could contribute a logarithmic number of operations (splitting a single number until it's no longer divisible by 2), and max heap operations are logarithmic per entry/removal, the overall efficiency of this algorithm should remain feasible under given constraints.

This approach successfully exploits the property of numbers being greatly reducible when even, paired with the property that reducing the largest numbers minimizes the range (deviation), aligning with the goal of minimizing the maximum pairwise difference in the array.

Solutions

  • C++
  • Java
  • Python
cpp
class MinimizeDeviation {
public:
    int findMinDeviation(vector<int>& elements) {
        int elementCount = elements.size();
        vector<int> adjustedValues[elementCount];
        for (int i = 0; i < elementCount; i++) {
            if (elements[i] % 2 == 0) {
                int currentValue = elements[i];
                adjustedValues[i].push_back(currentValue);
                while (currentValue % 2 == 0) {
                    currentValue /= 2;
                    adjustedValues[i].push_back(currentValue);
                }
            } else {
                adjustedValues[i].push_back(elements[i] * 2);
                adjustedValues[i].push_back(elements[i]);
            }
            reverse(adjustedValues[i].begin(), adjustedValues[i].end());
        }
        vector<vector<int>> sequences;
        for (int i = 0; i < elementCount; i++) {
            int length = adjustedValues[i].size();
            for (int j = 0; j < length; j++) {
                vector<int> seqPoint{adjustedValues[i][j], i, j};
                sequences.emplace_back(move(seqPoint));
            }
        }
        sort(sequences.begin(), sequences.end());
        int minimumDev = INT_MAX;
        int maximumElement = 0;
        for (int i = 0; i < elementCount; i++) {
            maximumElement = max(maximumElement, adjustedValues[i][0]);
        }
        int sizeRecord[elementCount];
        for (int i = 0; i < elementCount; i++) {
            sizeRecord[i] = adjustedValues[i].size();
        }
        for (auto& currentSequence : sequences) {
            int minValue = currentSequence[0];
            int elementIndex = currentSequence[1];
            int sequencePos = currentSequence[2];
            if (minimumDev > maximumElement - minValue) {
                minimumDev = maximumElement - minValue;
            }
            if (sequencePos + 1 == sizeRecord[elementIndex]) {
                return minimumDev;
            }
            int nextInSequence = adjustedValues[elementIndex][sequencePos + 1];
            maximumElement = max(maximumElement, nextInSequence);
        }
        return minimumDev;
    }
};

The code provided implements a solution for minimizing the deviation in an array of integers by possibly modifying the numbers. The process happens in several key steps, performed within the findMinDeviation function of the MinimizeDeviation class in C++.

  • Initialization of Local Variables:

    • elementCount stores the size of the input vector elements.
    • adjustedValues is a vector of vectors to store potential values each element can take after adjustment.
    • sequences, a vector of vectors, prepares for tracking each element and its indices in ordered form.
  • Adjusting Values Based on Even or Odd Status:

    • Loop through each element in the input.
    • If the element is even, continuously halve it until it becomes odd, storing each state.
    • If the element is odd, double it and keep the original, expanding the possibilities for minimum deviation.
  • Reverse the Order of Adjusted Values:

    • After obtaining all possible states for each element, reverse the vector to begin with the smallest potential value.
  • Flatten and Prepare for Sorting:

    • For each adjusted list of possible values of an element, a triple containing the value, its element index, and position in its adjusted vector is generated.
    • All these triples are stored in sequences, which are then sorted to prepare for comparison.
  • Calculating Minimum Deviation:

    • Initialize minimumDev to store the smallest difference found, and maximumElement to track the max value at any point during iteration.
    • Efficient comparison through sorted sequence triples to rapidly find conditions where the current minimal deviation may be updated.
    • If a selected sequence reaches its potential maximum, the loop can end early, returning the current smallest deviation.
  • Return the Computed Minimum Deviation:

    • Once all possibilities have been examined, or an early termination condition is met, minimumDev is returned as the result.

This code employs a combination of manipulating number properties (even and odd adjustments), vectors for dynamically adjusting iteration based on evolving conditions, and strategic sorting & iteration to efficiently approach the minimum deviation calculation.

java
class Solution {
    public int minDeviation(int[] elements) {
        int length = elements.length;
        // prepare values
        List<List<Integer>> options = new ArrayList<>();
        for (int i = 0; i < length; i++) {
            List<Integer> possibleValues = new ArrayList<>();
            if (elements[i] % 2 == 0) {
                int value = elements[i];
                possibleValues.add(value);
                while (value % 2 == 0) {
                    value /= 2;
                    possibleValues.add(value);
                }
            } else {
                possibleValues.add(elements[i] * 2);
                possibleValues.add(elements[i]);
            }
            // order values for easier handling
            Collections.reverse(possibleValues);
            options.add(possibleValues);
        }
        List<int[]> entries = new ArrayList<>();
        for (int i = 0; i < length; i++) {
            int count = options.get(i).size();
            for (int j = 0; j < count; j++) {
                entries.add(new int[] { options.get(i).get(j), i, j });
            }
        }
        entries.sort(Comparator.comparingInt(a -> a[0]));
        int deviation = Integer.MAX_VALUE;
        int upperBound = 0;
        for (int i = 0; i < length; i++) {
            upperBound = Math.max(upperBound, options.get(i).get(0));
        }
        for (int[] item : entries) {
            int lowerBound = item[0];
            int pos = item[1];
            int subIndex = item[2];
            if (deviation > upperBound - lowerBound) {
                deviation = upperBound - lowerBound;
            }
            if (subIndex + 1 == options.get(pos).size()) {
                return deviation;
            }
            int newValue = options.get(pos).get(subIndex + 1);
            upperBound = Math.max(upperBound, newValue);
        }
        return deviation;
    }
}

In the provided Java solution for the problem of minimizing deviation in an array, the aim is to calculate the minimum possible deviation between the maximum and minimum elements after modifying the array's elements. The elements can either be doubled if they are odd, or halved if they are even until they become odd.

Here's how the solution handles this:

  • Initialize an array of lists called options. Each list within holds possible values that each element in the input array could take after repeated modifications.
  • For each even element in the input array, generate a list of values by repeatedly halving it until it cannot be halved any further. All of these values, including the original, are possible states.
  • For each odd element, consider both the element itself and the element doubled (because the next modification would be halving).
  • Reverse the list of possible values for easier handling later.
  • Create a list of arrays called entries. Each array holds the value, its original position, and its index in its list of possible values.
  • Sort entries based on the values.
  • Start calculating the smallest possible deviation by initializing deviation to a very large value and determining upperBound, which is the maximum of the highest values in the options lists (the initial state).
  • Traverse the sorted entries, continuously updating the deviation if the current spread between upperBound and the current value (lowerBound) is smaller.
  • If you reach the end of available modifications for an element, return the current deviation.
  • Every time you move to a new possible value for any element, update upperBound if this new value exceeds the current upperBound.

What this algorithm effectively does is explore the range created by all possible modifications of every element, aiming to keep the maximum number of high potential values while determining when the spread between the highest and lowest reachable values is minimized. The exhaustive yet structured approach ensures that we capture the minimum possible deviation efficiently.

python
class Solution:
    def findMinDeviation(self, numbers: List[int]) -> int:
        transformed = []
        for number in numbers:
            series = []
            if number % 2 == 0:
                while number % 2 == 0:
                    series.append(number)
                    number //= 2
                series.append(number)
            else:
                series.append(number)
                series.append(number * 2)
            transformed.append(series[::-1])

        sequence_points = [(value, pos, sub_pos) for pos, series in enumerate(transformed)
                           for sub_pos, value in enumerate(series)]
        sequence_points.sort()
        minimum_deviation = float('inf')
        max_current = max(series[0] for series in transformed)

        for current_min, series_index, value_index in sequence_points:
            if max_current - current_min < minimum_deviation:
                minimum_deviation = max_current - current_min
            if value_index + 1 == len(transformed[series_index]):
                return minimum_deviation
            next_elem = transformed[series_index][value_index + 1]
            max_current = max(max_current, next_elem)

This Python solution aims to minimize the deviation in an array by leveraging a clever transformation and sorting technique.

  1. Start by transforming each element in the input list. If an element is even, keep dividing it by 2 and collect these values alongside the final odd result. For odd elements, collect the element itself and its double.

  2. Reverse each collected series to prepare for further steps. Store these reversed lists.

  3. Generate a list of tuples, where each tuple contains an element from the transformed arrays, along with its original series index and its index within the series. This assists in tracking while manipulating the data.

  4. Sort this list of tuples, primarily by the values, which helps in easy access to the current minimum element.

  5. Initialize minimum_deviation with infinity and determine the initial max_current from the first elements of all series.

  6. Iteratively examine each element in the sorted tuple list:

    • Update minimum_deviation if the difference between max_current and the current minimum is smaller than the previously recorded deviations.
    • Check if the current series can be extended (if there are more elements in the series). If not, conclude the process as further steps won't reduce the deviation.
    • Update max_current with the next element in the series if it's higher.

This approach effectively manages the operations needed to achieve a minimized deviation by utilizing transformed sequences, maintaining efficient track of the ongoing minimum values and adapting the maximum value dynamically. The solution’s complexity is chiefly governed by the sorting step, making it efficient given the constraints involving transformations and subsequent operations on them.

Comments

No comments yet.