找到数组的不相交序列的最大总和

时间:2015-06-21 18:02:49

标签: arrays algorithm

问题来自: https://www.hackerrank.com/contests/epiccode/challenges/white-falcon-and-sequence。 访问参考链接。

我有一个整数序列(-10 ^ 6到10 ^ 6)A。我需要选择A的两个连续的不相交子序列,比如x和y,它们是相同大小的n。

之后,您将计算∑x(i)y(n−i+1)(1索引)

给出的总和

我必须选择x和y以使总和最大化。

Eg: 
Input: 
12
1 7 4 0 9 4 0 1 8 8 2 4 

Output: 120

Where x = {4,0,9,4}
y = {8,8,2,4}

∑x(i)y(n−i+1)=4×4+0×2+9×8+4×8=120

现在,我想到的方法是O(n ^ 2),如下所示:

  1. 初始化两个变量l = 0r = N-1。这里,N是数组的大小。
  2. 现在,对于l=0,我将计算(l<r)的总和,它基本上是指从数组中的第0个位置开始的子序列。然后,我将递增l并递减r,以便得出从上面的位置+ 1开始并在右侧从right-1开始的子序列。
  3. 我可以使用更好的方法吗?什么更有效率?我想过排序,但我们不能对数字进行排序,因为这会改变数字的顺序。

2 个答案:

答案 0 :(得分:1)

为了回答这个问题,我们首先将S(i,j)定义为多个子序列项的最大和,对于子序列A [i ... j],当子序列x开始时位置i,子序列y在位置j结束。

例如,如果A = [1 7 4 0 9 4 0 1 8 8 2 4],则S(1,2)= 1 * 7 = 7且S(2,5)= 7 * 9 + 4 * 0 = 63。

计算S的递归规则是:S(i,j)= max(0,S(i + 1,j-1)+ A [i] * A [j]),结束条件为S (i,j)= 0 iff i> = j。

所请求的最终答案仅仅是对于i = 1..N,j = 1..N的所有组合的S(i,j)的最大值,因为S(i,j)值中的一个将对应到最大x,y子序列,因此将等于整个阵列的最大值。使用动态编程计算所有这样的S(i,j)值的复杂度是O(N ^ 2),因为在计算S(i,j)的过程中,我们还将计算最多N个其他S(i& #39;,j&#39;)值,但最终每个组合只计算一次。

def max_sum(l):
  def _max_sub_sum(i, j):
    if m[i][j]==None:
      v=0
      if i<j:
        v=max(0, _max_sub_sum(i+1, j-1)+l[i]*l[j])
      m[i][j]=v
    return m[i][j]

  n=len(l)
  m=[[None for i in range(n)] for j in range(n)]
  v=0
  for i in range(n):
    for j in range(i, n):
      v=max(v, _max_sub_sum(i, j))
  return v

答案 1 :(得分:0)

警告: 这种方法假设数字是非负的,所以这个解决方案没有回答海报的实际问题,现在已经澄清了允许负输入值。

技巧1

假设数字总是非负数,那么在给定它们相遇的位置的情况下,最好使序列尽可能宽。

Trick 2

我们可以通过对i的所有值求和来将总和更改为标准卷积。这产生了两倍的期望结果(因为我们得到x与y和y与x的乘积),但我们可以在结尾处除以2得到原始答案。

Trick 3

您现在正试图找到信号自身卷积的最大值。有一种标准方法可以使用快速傅立叶变换。一些图书馆将内置这种内容,例如在Scipy中有fftconvolve

Python代码

请注意,您不允许重复使用中心值(例如,对于序列1,3,2我们不能使x 1,3和y 3,1)所以我们需要检查替代值卷积输出。

我们现在可以通过以下方式在Python中计算答案:

import scipy.signal
A = [1, 7, 4, 0, 9, 4, 0, 1, 8, 8, 2, 4]
print max(scipy.signal.fftconvolve(A,A)[1::2]) / 2