给定一系列高度H
和一个量A
,在A
之间分配H
以最大化最小数组值的最佳方法是什么。
例1:
H = { 1, 3, 2, 2, 4 }
A = 4
output = { 3, 3, 3, 3, 4 }
例2:
H = { 1, 3, 2, 2, 4 }
A = 3
output = { 2.66, 3, 2.66, 2.66, 4 }
答案 0 :(得分:2)
O(N^2)
中的简单算法:
sort(T) // In ascending order; O(N log(N))
while amount > 0:
i := first index such that T[i] < T[i+1] # O(log(N)) at worst if you look for it from scratch each time, or (better) in average O(1) if you keep track of the previous such i and just look at the next values like @jdehesa does
amount_to_add := min(T[i+1] - T[i], amount / i) # Considering that T[N] = infinity makes it useless to do another loop if amount is big, it's all included here
for j <= i:
T[j] += amount_to_add
amount -= i * amount_to_add
在最糟糕的情况下,你会看到我曾经的每个位置,然后做一个长度为i的循环,因此O(N^2)
。
您只需存储您在第一个循环中必须执行的更改,然后在第二个循环中执行更新,即可实现O(Nlog(N))
:
sort(T) # In ascending order; O(N log(N))
lowest_value := T[0]
amount_to_add := zeros(N) # Array containing zeros initially
while amount > 0:
i := first index such that lowest_value < T[i+1] # O(log(N)) at worst. In practice probably O(1) if you keep track of the previous such i
amount_to_add[i] := min(T[i+1] - lowest_value, amount / i) # Considering that T[N] = infinity makes it useless to do another loop if amount is big, it's all included here
lowest_value += amount_to_add[i]
amount -= i * amount_to_add[i]
amount_to_add_incremental = 0
for j=N-1 to 0:
amount_to_add_incremental += amount_to_add[j]
T[j] += amount_to_add += amount_to_add_incremental
也许有更好的东西可以有效地计算O(N)
中的最终值,然后更新数组中的所有元素,在这种情况下你可以获得O(N)
,但你不会做比这更好。
例如,如果您认为amount
很大:例如amount >= N*max(T) - sum(T)
,只需要O(N)
次检查,那么您可以直接将T中的所有值设置为{{ 1}},需要max(T) + (amount - N*max(T) + sum(T))/N
时间。 O(N)
较小的情况更成问题。
答案 1 :(得分:2)
这是一个Python实现(对于NumPy或者类似的它可能更简洁但是无论如何):
def top_up(array, amount):
if not array:
return []
# Sort and keep the indices
array_sort, sort_idx = zip(*sorted(zip(array, range(len(array)))))
array_sort = list(array_sort)
# Take the smallest value
v = array_sort[0]
# Increase values from smaller to bigger
for i in range(1, len(array_sort)):
if amount <= 0:
break
if array_sort[i] == v:
continue
# When a different value is found increase previous to match
increase = min((array_sort[i] - v) * i, amount)
for j in range(i):
array_sort[j] += increase / i
amount -= increase
v = array_sort[i]
# Distribute remainder if any
if amount > 0:
for i in range(len(array_sort)):
array_sort[i] += amount / len(array_sort)
# Back to original order
result = [0] * len(array_sort)
for i, v in zip(sort_idx, array_sort):
result[i] = v
return result
测试:
top_up([1., 5., 7., 4., 3.], 6)
>>> [4.666666666666667, 5.0, 7.0, 4.666666666666667, 4.666666666666667]
更新:
采取&#34;增量变更存储&#34;这是一个小小的改进。来自gdelab's answer的想法:
def top_up(array, amount):
if not array:
return []
# Sort and keep the indices
array_sort, sort_idx = zip(*sorted(zip(array, range(len(array)))))
array_sort = list(array_sort)
# Take the smallest value
v = array_sort[0]
# Compute incremental changes
changes = [0] * len(array_sort)
for i in range(1, len(array_sort)):
if amount <= 0:
break
if array_sort[i] == v:
continue
# When a different value is found increase previous to match
increase = min((array_sort[i] - v) * i, amount)
changes[i - 1] = increase / i
amount -= increase
v = array_sort[i]
# Distribute remainder if any
changes[-1] = amount / len(array_sort)
# Perform the actual changes
change = 0
for i in reversed(range(len(changes))):
change += changes[i]
array_sort[i] += change
# Back to original order
result = [0] * len(array_sort)
for i, v in zip(sort_idx, array_sort):
result[i] = v
return result
答案 2 :(得分:0)
这是一个具有O(n log n)复杂度的伪代码算法:
# array : an array of land heights
# amount : an amount of water to fill up the lowland
tmparray = array.SortHighToLow # O(n log n) here, rest is O(n)
mean = array.MeanValue
count = array.Count;
for (height in tmparray)
begin
newmean = mean + (amount / count)
if (height <= newmean) break
count--
# recalculate mean for the remaining heights
mean = (mean * (count + 1) - height) / count
end
for (height in array)
begin
if (height < newmean) height = newmean # shall modify array
end
请注意,一旦获得newmean
,临时数组就会被丢弃,这足以使原始数组均匀。