假设列表房由0(= x)的对(x,pop)组成, 4 * L的位置和流行的人口。
我们想要最大化的目标函数是
def revenue(i):
return sum(pop * min((i-j)%(4*L), 4*L - (i-j)%(4*L)) for j,pop in houses)
朴素算法O(LN)算法简单:
max_revenue = max(revenue(i) for i in range(4*L))
但是,完全重新评估每个地点的收入是非常浪费的。
为了避免这种情况,请注意这是一个分段线性函数;所以它的导数是分段常数,不等式在两点上:
>在房子我,衍生物从斜坡变化到2 *人口[i]
>在岛上对面的位置,衍生物从斜坡变化到斜坡 – 2 *人口[i]
这使事情很简单:
>我们只需要检查实际的房屋或对面的房子,所以复杂度下降到O(N²)。
>我们知道如何更新房屋i-1到房屋i的坡度,只需要O(1)个时间。
>由于我们知道位置0的收入和斜率,并且由于我们知道如何迭代地更新斜率,所以复杂性实际上下降到O(N):在两个连续房屋/对立房屋之间,我们可以将通过距离斜率获得收入差额。
所以完整的算法是:
def algorithm(houses, L):
def revenue(i):
return sum(pop * min((i-j)%(4*L), 4*L - (i-j)%(4*L)) for j,pop in houses)
slope_changes = sorted(
[(x, 2*pop) for x,pop in houses] +
[((x+2*L)%(4*L), -2*pop) for x,pop in houses])
current_x = 0
current_revenue = revenue(0)
current_slope = current_revenue - revenue(4*L-1)
best_revenue = current_revenue
for x, slope_delta in slope_changes:
current_revenue += (x-current_x) * current_slope
current_slope += slope_delta
current_x = x
best_revenue = max(best_revenue, current_revenue)
return best_revenue
为了保持简单,我使用sorted()来合并两种类型的斜率变化,但这并不是最优的,因为它具有O(N log N)的复杂性。如果想要更好的效率,可以在O(N)时间内生成对应于对面房屋的排序列表,并将其与O(N)中的房屋列表合并(例如使用标准库的heapq.merge) 。如果要最小化内存使用情况,您也可以从迭代器而不是列表流式传输。
TLDR:该解决方案实现了O(N)的最低可行复杂度。