【问题标题】:minimum moves to balance an array最小移动以平衡阵列
【发布时间】:2012-02-17 05:46:02
【问题描述】:

我们有一个由 n 个正整数组成的数组。一个可接受的做法是将一个元素增加 1 并将其相邻元素之一减少 1。

最终数组中的最小值和最大值最多相差 1。这样做的最小移动次数是多少?

例如,如果初始数组是 {5, 6, 4, 1, 10},则答案是 5,最终数组可能是 {5, 5, 5, 5, 6}。

【问题讨论】:

  • 我没有任何多项式算法。
  • SO 不会只给你算法。你有没有想过这个问题并想出一些直觉?
  • 如果我们知道目标数组,它将在 O(n) 中求解;只是扫阵并贪婪地移动。我猜可能存在一个动态解决方案,比如在数组的后缀中有 k 个最大值,但之前需要一些贪婪的动作。

标签: algorithm adhoc


【解决方案1】:

我们可以使用分治法来解决这个问题。

我们知道所有元素的最终值一定是数组中所有元素的AVERAGE。如果平均值不是整数,那么我们可以定义两个值 - MAX 和 MIN,这样 MAX 是平均值的上限,MIN 是平均值的下限。 (http://en.wikipedia.org/wiki/Floor_and_ceiling_functions)

现在将数组分成两等份。 [ 0 - n/2 ] 和 [ n/2 +1 到 n-1 ]。如果 n 是奇数,前半部分会更小,但这没关系。

对于每一半,计算所有元素的平均值。这个平均值必须等于 MAX 或 MIN。如果不是,则必须根据需要提高或降低该平均值。

现在要注意的一件事是,子数组的平均值不能通过仅涉及该子数组中的元素的操作来修改。因此,任何更改都需要在第 n/2 和第 n/2+1 元素之间进行操作。

另一点需要注意的是,如果一个子数组的平均值小于要求,另一个子数组的平均值大于要求。

因此可以很容易地在两个中间元素之间进行适当的操作。

现在将每个子数组一分为二,然后重复这个过程。

[注意:计算子数组平均值所需的重复求和操作可以在对数时间内执行,用于更新和求和操作,使用区间树http://en.wikipedia.org/wiki/Interval_tree]

【讨论】:

  • 您的解决方案中有一个贪婪的事实:您在两个中间元素之间移动 1 的次数越少越好。(为什么?)
  • 因为,就像我说的那样,增加/减少任何子数组的平均值的唯一方法是将值从该子数组移入/移出另一个子数组。为什么这是必需的?因为我们知道在最终数组中,该数组中的任何子数组必须具有 MIN 和 MAX 之间的平均值,包括两者。另外,我认为 O(n) 贪心解决方案是不可能的(我的至少是 O(n log n),可能更多取决于求和操作的实现方式)
  • 您在子数组之间移动尽可能少的 1,只是为了将它们的平均值变为 [MIN,MAX],并且您不再执行移动;以后移动更多的 1 是否有帮助?如果您的算法是正确的,则可能会在每次工作时删除 1 长度的子数组:每次移动直到第一个元素的值和其余元素的平均值变为 [MIN,MAX];它将在 O(n) 中工作。分而治之对你的算法有什么帮助?
猜你喜欢
  • 1970-01-01
  • 2020-05-19
  • 2011-12-24
  • 2021-04-30
  • 1970-01-01
  • 2012-10-15
  • 2012-05-26
  • 2022-06-15
  • 1970-01-01
相关资源
最近更新 更多