给出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;
}
有人可以帮助我提供解决此问题的正确方法吗?
答案 0 :(得分:8)
上面的代码有效,但是我没有找到太多解释,所以我会尝试添加一些以帮助培养直觉。
对于任何给定的塔,如果您选择将其高度从 Hi 增加到 Hi + K,那么您还可以增加所有较短塔的高度,因为这不会影响最大值。同样,如果您选择将塔的高度从 Hi 减小到 Hi - K,那么您还可以降低所有较高塔的高度。
我们将利用这一点,我们有n个建筑物,我们将尝试使每个建筑物最高,然后看看使哪个建筑物最高给我们的高度范围最小(这是我们的答案)。
让我解释一下:
所以我们想要做的是 -
1) 我们首先对数组进行排序(你很快就会明白为什么)。
2)然后对于从 i = 0 到 n-2[1] 的每个建筑物,我们尝试使其最高(通过向建筑物添加 K,向其左侧的建筑物添加 K 并减去 K从它右边的建筑物)。
因此,假设我们正在建造 Hi,我们已经将 K 加到它和它之前的建筑物中,并从之后的建筑物中减去 K它。
所以建筑物的最小高度现在将是 min(H0 + < em>K、Hi+1 - K)、
ie min(第一个建筑物 + K,右边的下一个建筑物 - K)。
(注意:这是因为我们对数组进行了排序。举几个例子说服自己。)
同样,建筑物的最大高度将为 max(Hi + K, Hn-1 - K),
ie 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;
}
}
答案 1 :(得分:1)
此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)
mx=max(arr[n-1]-k, arr[i]+k)
ans = min(ans, mx-mn)
return ans
答案 2 :(得分:1)
这是一个解决方案:-
但在开始解决方案之前,这里有一些需要了解的信息。在最好的情况下,最小差异将为零。这只会在两种情况下发生 - (1) 数组包含重复项或 (2) 对于一个元素,比如“x”,数组中存在另一个元素,其值为“x + 2*k”。>
这个想法很简单。
这是该算法的 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;
}
答案 3 :(得分:0)
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 ++代码,它通过了所有测试用例。
答案 4 :(得分:0)
这是 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;
}
答案 5 :(得分:0)
class Solution {
public:
int getMinDiff(int arr[], int n, int k) {
sort(arr, arr+n);
int diff = arr[n-1]-arr[0];
int mine, maxe;
for(int i = 0; i < n; i++)
arr[i]+=k;
mine = arr[0];
maxe = arr[n-1]-2*k;
for(int i = n-1; i > 0; i--){
if(arr[i]-2*k < 0)
break;
mine = min(mine, arr[i]-2*k);
maxe = max(arr[i-1], arr[n-1]-2*k);
diff = min(diff, maxe-mine);
}
return diff;
}
};