Минимизируйте максимальную разницу между высотами

Даны высоты n башен и значение k. Нам нужно либо увеличить, либо уменьшить высоту каждой башни на k (только один раз), где k > 0. Задача состоит в том, чтобы минимизировать разницу между высотами самой длинной и самой короткой башни после модификаций и вывести эту разницу.

У меня есть интуиция, стоящая за решением, но я не могу комментировать правильность решения ниже.



// C++ program to find the minimum possible 
// difference between maximum and minimum 
// elements when we have to add/subtract 
// every number by k 
#include <bits/stdc++.h> 
using namespace std; 
  
// Modifies the array by subtracting/adding 
// k to every element such that the difference 
// between maximum and minimum is minimized 
int getMinDiff(int arr[], int n, int k) 
{ 
    if (n == 1) 
       return 0; 
  
    // Sort all elements 
    sort(arr, arr+n); 
  
    // Initialize result 
    int ans = arr[n-1] - arr[0]; 
  
    // Handle corner elements 
    int small = arr[0] + k; 
    int big = arr[n-1] - k; 
    if (small > big) 
       swap(small, big); 
  
    // Traverse middle elements 
    for (int i = 1; i < n-1; i ++) 
    { 
        int subtract = arr[i] - k; 
        int add = arr[i] + k; 
  
        // If both subtraction and addition 
        // do not change diff 
        if (subtract >= small || add <= big) 
            continue; 
  
        // Either subtraction causes a smaller 
        // number or addition causes a greater 
        // number. Update small or big using 
        // greedy approach (If big - subtract 
        // causes smaller diff, update small 
        // Else update big) 
        if (big - subtract <= add - small) 
            small = subtract; 
        else
            big = add; 
    } 
  
    return  min(ans, big - small); 
} 
  
// Driver function to test the above function 
int main() 
{ 
    int arr[] = {4, 6}; 
    int n = sizeof(arr)/sizeof(arr[0]); 
    int k = 10; 
    cout << "\nMaximum difference is "
        << getMinDiff(arr, n, k); 
    return 0; 
} 

Может ли кто-нибудь помочь мне найти правильное решение этой проблемы?


person Ajay Singh    schedule 20.07.2020    source источник
comment
Некоторые рекомендуемые чтения: Почему я не должен #include <bits/stdc++.h>? и < a href="https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice"> Почему using namespace std; считается плохой практикой?   -  person ChrisMM    schedule 20.07.2020
comment
В чем проблема? Может ли кто-нибудь помочь мне предоставить правильное решение, это не вопрос, который будет хорошо принят на SO.   -  person ChrisMM    schedule 20.07.2020
comment
Отвечает ли это на ваш вопрос? Минимальная разница между высотами башен?   -  person Go Beyond    schedule 22.02.2021
comment
stackoverflow.com/questions /32233916/› Эта ссылка объясняет это довольно хорошо.   -  person DEEPANSHU RAWAT    schedule 30.03.2021


Ответы (5)


Приведенные выше коды работают, однако я не нашел много объяснений, поэтому я попытаюсь добавить некоторые из них, чтобы помочь развить интуицию.

Для любой башни, если вы решите увеличить ее высоту с Hi до Hi + K, то вы также можете увеличить высоту всех более коротких башен, так как это не повлияет на максимум. Точно так же, если вы решите уменьшить высоту башни с Hi до Hi − K, то вы также можете уменьшить высоту всех более высоких башен.
Мы воспользуемся этим, у нас есть n зданий, и мы постараемся сделать каждое из них самым высоким и посмотрим, какое из зданий будет самым высоким, что даст нам наименьший диапазон высот (это наш ответ).
Поясню:

Итак, что мы хотим сделать, это -
1) Сначала мы сортируем массив (вы скоро поймете, почему).

2) Затем для каждого здания от i = 0 до n-2[ 1], мы пытаемся сделать его самым высоким (добавляя K к зданию, добавляя K к зданиям слева от него и вычитая K из зданий справа).

Допустим, мы строим Hi, мы добавили к нему букву K и здания до него и вычел K из зданий после него.

Таким образом, минимальная высота зданий теперь будет min(H0 + K, Hi+1 – K),
т.е. мин(1-е здание + K, следующее здание справа - K)
.

(Примечание: это потому, что мы отсортировали массив. Убедитесь сами, взяв несколько примеров.)

Аналогично, максимальная высота зданий будет max( Hi + K, Hn-1 – K),
т. е. max(текущее здание + K, последнее здание справа - K)
.

3) max - min дает вам диапазон.

[1]Обратите внимание, что когда i = n-1. В этом случае после текущего здания нет здания, поэтому мы добавляем K к каждому зданию, поэтому диапазон будет просто height[n-1] - height[0], так как K добавляется ко всему, поэтому он отменяет вне.

Вот реализация Java, основанная на приведенной выше идее:

class Solution {
    int getMinDiff(int[] arr, int n, int k) {
        Arrays.sort(arr);
        int ans = arr[n-1] - arr[0];
        int smallest = arr[0] + k, largest = arr[n-1]-k;
        for(int i = 0; i < n-1; i++){
            int min = Math.min(smallest, arr[i+1]-k);
            int max = Math.max(largest, arr[i]+k);
            if(min < 0) 
                continue;
            ans = Math.min(ans, max-min);
        }
        return ans;
    }
}
person Ayush    schedule 25.01.2021

Этот код Python может вам помочь. Код говорит сам за себя.

def getMinDiff(arr, n, k):
    arr = sorted(arr)
    ans = arr[-1]-arr[0] #this case occurs when either we subtract k or add k to all elements of the array
    for i in range(n):
        mn=min(arr[0]+k, arr[i]-k) #after sorting, arr[0] is minimum. so adding k pushes it towards maximum. We subtract k from arr[i] to get any other worse (smaller) minimum. worse means increasing the diff b/w mn and mx
        mx=max(arr[n-1]-k, arr[i]+k) # after sorting, arr[n-1] is maximum. so subtracting k pushes it towards minimum. We add k to arr[i] to get any other worse (bigger) maximum. worse means increasing the diff b/w mn and mx
        ans = min(ans, mx-mn)
    return ans
person Himanshu Singh    schedule 08.08.2020
comment
Также добавьте оператор if, чтобы проверить, больше ли arr[i] k. У нас не может быть отрицательной высоты, не так ли? - person Nikhil.Nixel; 04.01.2021
comment
Вы можете сказать, почему это работает? - person rahul sharma; 05.01.2021
comment
@rahulshharma Я добавил еще несколько комментариев в код. посмотрите, поможет ли это. Попробуйте пробный запуск кода, вы получите интуицию. - person Himanshu Singh; 05.01.2021

int getMinDiff(int a[], int n, int k) {
        sort(a,a+n); 
        int i,mx,mn,ans;
        ans = a[n-1]-a[0];  // this can be one possible solution
        
        for(i=0;i<n;i++)
        {
            if(a[i]>=k)  // since height of tower can't be -ve so taking only +ve heights
            {
                mn = min(a[0]+k, a[i]-k);
                mx = max(a[n-1]-k, a[i-1]+k);
                ans = min(ans, mx-mn);
            }
        }
        return ans;
    }

Это код C++, он прошел все тесты.

person MeeeCoder    schedule 10.12.2020
comment
Можете ли вы сказать, почему это работает? У меня не было интуиции, стоящей за этим? - person rahul sharma; 05.01.2021

Вот решение: -

Но прежде чем перейти к решению, вот некоторая информация, необходимая для его понимания. В лучшем случае минимальная разница будет равна нулю. Это может произойти только в двух случаях: (1) массив содержит дубликаты или (2) для элемента, скажем, «x», в массиве существует другой элемент со значением «x + 2*k».

Идея довольно проста.

  1. Сначала мы отсортировали массив.
  2. Далее мы попытаемся найти либо оптимальное значение (для которого ответ будет равен нулю), либо, по крайней мере, ближайшее число к оптимальному значению, используя >Двоичный поиск

Вот реализация алгоритма Javascript: -

function minDiffTower(arr, k) {
    arr = arr.sort((a,b) => a-b);
    let minDiff = Infinity;
    let prev = null;

    for (let i=0; i<arr.length; i++) {
        let el = arr[i];
        
        // Handling case when the array have duplicates
        if (el == prev) {
            minDiff = 0;
            break;
        }
        prev = el;

        let targetNum = el + 2*k; // Lets say we have an element 10. The difference would be zero when there exists an element with value 10+2*k (this is the 'optimum value' as discussed in the explaination
        let closestMatchDiff =  Infinity; // It's not necessary that there would exist 'targetNum' in the array, so we try to find the closest to this number using Binary Search
        let lb = i+1;
        let ub = arr.length-1;
        while (lb<=ub) {
            let mid = lb + ((ub-lb)>>1);
            let currMidDiff =  arr[mid] > targetNum ? arr[mid] - targetNum : targetNum - arr[mid];
            closestMatchDiff = Math.min(closestMatchDiff, currMidDiff); 
            if (arr[mid] == targetNum) break; // in this case the answer would be simply zero, no need to proceed further
            else if (arr[mid] < targetNum) lb = mid+1;
            else ub = mid-1;
        }
        minDiff = Math.min(minDiff, closestMatchDiff);
    }
    return minDiff;
}
person Mojo Jojo    schedule 28.03.2021

Вот код C++, я продолжил с того места, где вы остановились. Код говорит сам за себя.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int minDiff(int arr[], int n, int k)
{
    // If the array has only one element.
    if (n == 1)
    {
        return 0;
    }
    //sort all elements
    sort(arr, arr + n);

    //initialise result
    int ans = arr[n - 1] - arr[0];

    //Handle corner elements
    int small = arr[0] + k;
    int big = arr[n - 1] - k;
    if (small > big)
    {
        // Swap the elements to keep the array sorted.
        int temp = small;
        small = big;
        big = temp;
    }

    //traverse middle elements
    for (int i = 0; i < n - 1; i++)
    {
        int subtract = arr[i] - k;
        int add = arr[i] + k;

        // If both subtraction and addition do not change the diff.
        // Subtraction does not give new minimum.
        // Addition does not give new maximum.
        if (subtract >= small or add <= big)
        {
            continue;
        }

        // Either subtraction causes a smaller number or addition causes a greater number.
        //Update small or big using greedy approach.
        // if big-subtract causes smaller diff, update small Else update big
        if (big - subtract <= add - small)
        {
            small = subtract;
        }
        else
        {
            big = add;
        }
    }
    return min(ans, big - small);
}

int main(void)
{
    int arr[] = {1, 5, 15, 10};
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 3;
    cout << "\nMaximum difference is: " << minDiff(arr, n, k) << endl;
    return 0;
}
person Adarsh_V_Desai    schedule 30.04.2021