以这样的方式填充数组,使每个元素等于两个数字的最小和

Filling an array in such a way that each element equal to minimum sum of two numbers such that

本文关键字:于两个 元素 数字 方式 填充 数组      更新时间:2023-10-16

给定一个数组(只包含整数),并且已经有k个元素:a1, a2, ....<> k
我需要填充剩余的(n - k)元素(数组总共有n元素)。
n的值 10 ^ 3 1 & lt; = & lt; k = n
每个ai的值是两个数的最小和,使得这两个数的位置之和等于i

下面是伪代码(我的算法):

for i = k + 1 to n
  a[i] = max_value
  for j = 1 to (i / 2)
    a[i] = min(a[i], a[j] + a[i - j])
时间复杂度:O(n ^ 2)

问题是:有没有其他更快的方法?
我正在寻找任何数据结构或算法,可以找到每个a I 小于O(n)的值。

P/S:这是我的程序中的一个过程,所以我需要尽快完成。

您可以通过使用线程并行运行您的最小值检查来提高程序速度。例如,您可以运行4个线程,每个线程检查j范围的1/4。这将略微提高速度,但您的算法仍然需要O(n^2)的运行时间。

我同意你很可能不能超过O(n^2)的评论。所以你最好的选择可能是尝试这样的事情来优化你的代码,以减少n^2前面的系数。

创意1

AFAICT这不能保证在O(n^2)上得到改进,但它应该在实践中使内循环周期的数量减少很多。基本的想法是,我们可以在内部循环中以不同的顺序测试对,这使我们能够在很多时候提前完成。具体来说,我们首先对数字的位置进行排序,并将其存储在s[]中,因此a[s[i]]a[]中第i小的数字。然后在主内循环中,我们用a[s[j]]代替a[j] (a[i - s[j]]代替a[i - j])按第一项递增的顺序形成成对和。这给了我们两种方法来提前停止内循环:

  1. 如果a[s[j]] >= a[i],那么我们可以停止,因为每个后面的和必须更大,因为它们每个(a[s[j+1]]等)的第一项必须至少与迄今为止的最佳解(已经在a[i]中)一样大,而另一项永远不能是负的。
  2. 如果a[i - s[j]] <= a[s[j]](也就是说,如果下一个最小数的"伙伴"小于或等于它),我们可以停止,原因更复杂。相反,假设后来有一些更好的配对和a[s[m]] + a[i - s[m]](即m > j)。我们知道第一项a[s[m]],必须至少和现在的第一项a[s[j]]一样大因为我们是按递增顺序访问第一项,m > j;因此,为了使配对和a[s[m]] + a[i - s[m]]优于(即小于)a[s[j]] + a[i - s[j]],它的第二项a[i - s[m]]必须小于当前的第二项a[i - s[j]]。(这不是充分条件,但在这里无关紧要。)但是由于我们刚刚观察到a[i - s[j]] <= a[s[j]],我们也知道a[i - s[m]] < a[s[j]],这意味着a[i - s[m]]必须出现在作为我们之前已经处理过的对和中的第一项 !这与m > j相矛盾,意味着不存在更好的配对和,所以我们可以安全地停止。

我期望第二个条件能够移除很多内循环;第一种方法可能只对有少量小数和大量非常高的数字的数据集有很大帮助,并且可以用小数的对和来覆盖大多数位置。

额外的效率:如果我们实现上面的第二个条件,那么我们实际上不需要单独的j < i / 2循环终止测试,因为在检查任何i / 2 + 1对和之后,我们必须至少遇到两次对和(一次交换了第一项和第二项),这将导致条件2触发并退出循环。

伪代码:

s[1 .. k] = 1 .. k
sort s using comparator function comp(i, j) { a[i] < a[j] }
for i = k + 1 to n
  a[i] = max_value
  for (j = 1; a[s[j]] < a[i] && a[i - s[j]] > a[s[j]]; ++j)
    a[i] = min(a[i], a[s[j]] + a[i - s[j]])