【问题标题】:Filling an array in such a way that each element equal to minimum sum of two numbers such that以这样的方式填充数组,使得每个元素等于两个数字的最小和,使得
【发布时间】:2014-08-09 04:50:40
【问题描述】:

给定一个已经包含前 k 个元素的数组(仅包含 个整数):a1、a2, ....一个k
我需要填充剩余的 (n - k) 元素(数组总共有 n 元素)。
n 的值约为 10 ^ 31 。
每个 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)

问题:有没有其他方法可以更快地做到这一点?
我正在寻找可以在小于 O(n) 的时间内找到每个 ai 值的任何数据结构或算法。

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

【问题讨论】:

  • 如果它是真正的代码,你真正想要做什么?这看起来像 XY problem
  • 我添加了描述,这就是我的代码(直截了当)
  • 我看了你的编辑。你的问题还是太抽象了。你的代码试图解决什么真正的问题?
  • 我没有严格的证明,但我强烈认为 O(n) 无法改进。恕我直言,这仍然是一个好问题 +1
  • @ColonelPanic:例如:我们有a1 = 10, a2 = 6, a3 = 4,我们需要计算a4, a5, .... 以下是计算:a4 = min(a1 + a3, a2 + a2) = 12 ; a5 = min(a1 + a4, a2 + a3) = 10; a6 = min(a1 + a5, a2 + a4, a3 + a3) = 8... 以此类推。

标签: c++ arrays algorithm data-structures


【解决方案1】:

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

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

【讨论】:

    【解决方案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]] 必须作为一个出现我们之前已经处理过的pair-sum中的第一个term!这与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]])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多