拆分数组以找到分布式环境中两个子数组之和之间的最小差异

时间:2019-06-07 14:02:04

标签: javascript algorithm distributed-computing distributed distributed-system

这个问题我昨天被问到了。我必须编写代码将数组分为两部分,以使这两部分之和之间的差异最小。

这是我写的复杂度为 O(n)

的代码
function solution(a) {
  let leftSum = 0;
  let rightSum = a.reduce((acc, value) => acc + value ,0);
  let min = Math.abs(rightSum - leftSum);
  a.forEach((item, i) => {
   leftSum += a[i];
   rightSum -= a[i]; 
   const tempMin = Math.abs(rightSum - leftSum);
   if(tempMin < min) min = tempMin;
  })
  return min;
}

但是随后我被问及输入数组的长度是否为1000万,如何在分布式环境中解决此问题?

我是分布式编程的新手,需要帮助。

3 个答案:

答案 0 :(得分:3)

如果您有N个节点,则将数组拆分为N个顺序子数组;这将给您N个连续的总和。通过以确定哪个子数组包含所需的分割点。 “之前”和“之后”总和之间的差异是您对下一阶段的偏向目标...

现在将“中间”数组分成N个片段。同样,您会寻找合适的分割点,只是现在您知道想要的确切结果了(因为您拥有数组和和缺失的差)。

重复第二段,直到您可以将整个子数组放入一个节点 中,这是完成项目计算的最快方法。


您可以通过将每个值的累加总和稍微加快速度。这样您可以在每个阶段更快地找到合适的分割点,因为您可以在第一个阶段之后的每个阶段使用二进制或内插搜索。

答案 1 :(得分:2)

给定一个长度为N的数组,并给定M个可用节点,将该数组分成大小为N / M的块。每个节点计算其块的总和,并进行报告。通过将部分和相加来计算总数。然后,将总和和部分和分配给每个节点。每个节点确定其块内的最佳分割点(局部最小值),并进行报告。全局最小值是根据局部最小值计算的。

例如,如果数组有1000万个条目,并且有200个可用节点,则块大小为50000。因此,每个节点接收50000个数字,并报告总和。数组的总和是通过将200个部分总和相加得出的。然后,将为每个节点提供总计以及200个部分和。现在,每个节点上的信息包括

  • 组号
  • 该块的50000个数组条目
  • 总计数组
  • 200个部分款项

根据该信息,每个节点都可以计算其局部最小值。全局最小值是从200个局部最小值中得出的。

在理想情况下,网络带宽是无限的,网络延迟是零,并且可以使用任意数量的节点,块大小应为sqrt(N)。因此,每个节点接收sqrt(N)个数组元素,然后接收sqrt(N)个部分和。在这些理想条件下,运行时间为O(sqrt(N)),而不是O(N)

当然,在现实世界中,尝试分发这样的问题没有任何意义。通过网络发送阵列元素的时间(每个阵列元素)很长。比在单台计算机上解决问题所需的时间(每个阵列元素)大得多。

答案 2 :(得分:1)

假定该数组顺序存储在几个节点N_1,...,N_k上。您原始算法的一个简单的分布式版本可能如下。

  1. 在每个N_i上,计算存储在N_i上的子数组的总和s_i并将其发送到控制节点M
  2. 在节点M上,使用s_1,...,s_k为每个N_i的左子数组边界计算leftSum_irightSum_i并将它们发送回N_i
  3. 在每个N_i上,使用leftSum_irightSum_i进行搜索以找到最小的min_i并将其发送回M
  4. 在节点M上,根据min,... min_i
  5. 计算全局最小值min_k

附注:您可以优化原始算法以仅保留值rightSum - leftSum,而不保留两个单独的值leftSumrightSum。分布式版本也可以进行相应的优化。