Wednesday, August 30th

Replacements to Sort

Given an array of integers, with a single operation one can replace an element by any two elements that sum to the original element.  Find the minimum number of operations required to sort the array.

A hip replacement.  Courtesy of Carl Jones et al via Wikipedia.  Shared under the Creative Commons Attribution 4.0 International license.  No changes made.

A couple of key observations:

  1. It doesn't make sense to reduce the last element in the array
  2. When reducing an element, it makes sense to try and reduce it into as few chunks as possible that are equal to or less than the element to the right

We implement a greedy algorithm that operates in linear time

First we initialize our answer variable and the length of the array 

long long minimumReplacement(vector<int>& nums) {
long long answer = 0;
int n = nums.size();
        ...
    }

Next we loop through elements from right to left.  We do not need to perform calculations on the last element, so we begin at index i=n-2.  If an element on the left is less than or equal to the element on the right, then it's sorted properly and requires no further action

for (int i = n - 2; i >= 0; i--) {
if (nums[i] <= nums[i + 1]) {
continue;
}
        ...
    }

If an element is larger than the element to its right, then we must take action to reduce it.  We want as few reduction operations as possible, so we divide it into chunks as close as we can to the element on the right

The number of elements that result from dividing element i into chunks as close to element i+1 results in this number of elements:

    long long numElements = ceil((nums[i] + nums[i + 1] - 1) / (nums[i + 1]));

Since we already have 1 element in the array, this means an addition of the number of elements less one:

    answer += numElements - 1;

We don't actually insert the new elements, we just count them for the answer.  Moreover, we change the element at i equal to its value were the new values inserted, which completes the for loop

   for (int i = n - 2; i >= 0; i--) {
                ...
        nums[i] = nums[i] / numElements;
    }

Finally, we return the answer

    long long minimumReplacement(vector<int>& nums) {
        ...
        return answer;
    }       

This problem definitely seems daunting at first, but remarkably has a greedy solution in a few lines.  Settling down and making a couple sharp observations dramatically reduces the problem's complexity

Thank you to a great Editorial with many helpful diagrams

Comments

Popular posts from this blog

Wednesday, September 20th

Monday, September 11th

Tuesday, September 19th