algorithm - 找到将序列拆分为 2 以最小化总和差异的算法

标签 algorithm

<分区>

问题是:给定一个数字序列,将这些数字分成 2 个序列,使两个序列之间的差异最小。例如,给定序列:[5, 4, 3, 3, 3] 解决方案是:
[5, 4] -> 总和为 9
[3, 3, 3] -> 总和为 9
差异为0

换句话说,你能找到一种算法(首选 C 语言),给定一个整数输入向量(可变大小),可以输出两个向量,其中两个向量之和之间的差值最小吗?
应避免暴力算法。

为了确保获得正确的解决方案,最好在基准测试中比较您的算法和暴力算法之间的结果。

最佳答案

这听起来像是一个子数组问题(这是我对“序列”的解释)。

意味着 5, 4, 3, 3, 3 的唯一可能性是:

| 5, 4, 3, 3, 3  =>  0 - 18 => 18
 5 | 4, 3, 3, 3  =>  5 - 13 => 8
 5, 4 | 3, 3, 3  =>  9 -  9 => 0
 5, 4, 3 | 3, 3  => 12 -  6 => 6
 5, 4, 3, 3 | 3  => 15 -  3 => 12
 5, 4, 3, 3, 3 | => 18 -  0 => 18 (same as first)

它就像比较每个索引两边的总和一样简单。

代码:(未经测试)

int total = 0;
for (int i = 0; i < n; i++)
  total += arr[i];
int best = INT_MAX, bestPos = -1, current = 0;
for (int i = 0; i < n; i++)
{
  current += arr[i];
  int diff = abs(current - total);
  if (diff < best)
  {
    best = diff;
    bestPos = i;
  }
  // else break; - optimisation, may not work
}

printf("The best position is at %d\n", bestPos);

上面是O(n),从逻辑上讲,你不能做得比这更好。

您可以通过对序列执行类似二进制搜索的过程来稍微优化上面的内容,以得到 n + log n 而不是 2n,但两者都是 O(n)。基本伪代码:

sum[0] = arr[0]
// sum[i] represents sum from indices 0 to i
for (i = 1:n)
  sum[i] = sum[i-1] + arr[i]
total = sum[n]
start = 0
end = n
best = MAX
repeat:
  if (start == end) stop
  mid = (start + end) / 2
  sumFromMidToN = sum[n] - sum[mid]
  best = max(best, abs(sumFromMidToN - sum[mid]))
  if (sum[mid] > sumFromMidToN)
    end = mid
  else if (sum[mid] < sumFromMidToN)
    start = mid
  else
    stop

如果它实际上是子集,那么,如前所述,它似乎是the Partition problem 的优化版本。 , 这要困难得多。

关于algorithm - 找到将序列拆分为 2 以最小化总和差异的算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15472906/

相关文章:

algorithm - 给定一个只包含0和1的矩阵,并且矩阵的每一行都已排序,请找出哪一行包含最多的1

c++ - 使用加法、减法和连接将数字组合成给定数字的方法

algorithm - 将 MongoDB 地理空间索引与 3d 数据结合使用

algorithm - 毛里求斯国旗问题

algorithm - 为什么这个解决方案说 DFS 必须反向运行?

python - 如何填补元组列表中的空白

algorithm - 最长非递减序列 - n log n?

子图同构检测算法

algorithm - 快速排序分区程序(Lomuto)中的交换条件?

python - 图书的 CSV 解析