简体   繁体   English

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

[英]finding maximum sum of a disjoint sequence of an array

Problem from : https://www.hackerrank.com/contests/epiccode/challenges/white-falcon-and-sequence . 问题来自: https : //www.hackerrank.com/contests/epiccode/challenges/white-falcon-and-sequence Visit link for references. 访问链接以获取参考。

I have a sequence of integers (-10^6 to 10^6) A. I need to choose two contiguous disjoint subsequences of A, let's say x and y, of the same size, n. 我有一个整数序列(-10 ^ 6到10 ^ 6)A。我需要选择A的两个连续的不相交的子序列,假设x和y的大小相同,即n。

After that you will calculate the sum given by ∑x(i)y(n−i+1) (1-indexed) 之后,您将计算由∑x(i)y(n−i+1) (1索引)给出的总和

And I have to choose x and y such that sum is maximised. 而且我必须选择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

Now, the approach that I was thinking of for this is something in lines of O(n^2) which is as follows: 现在,我正在考虑的方法是在O(n ^ 2)行中进行如下操作:

  1. Initialise two variables l = 0 and r = N-1 . 初始化两个变量l = 0r = N-1 Here, N is the size of the array. 在此, N是数组的大小。
  2. Now, for l=0 , I will calculate the sum while (l<r) which basically refers to the subsequences that will start from the 0th position in the array. 现在,对于l=0 ,我将计算总和,而(l<r)基本上是指将从数组中第0个位置开始的子序列。 Then, I will increment l and decrement r in order to come up with subsequences that start from the above position + 1 and on the right hand side, start from right-1 . 然后,我将递增l并递减r ,以得出从上述位置+ 1开始并在右侧从right-1开始的子序列。

Is there any better approach that I can use? 有什么更好的方法可以使用吗? Anything more efficient? 还有效率更高的吗? I thought of sorting but we cannot sort numbers since that will change the order of the numbers. 我想到了排序,但是我们不能对数字进行排序,因为那样会改变数字的顺序。

To answer the question we first define S(i, j) to be the max sum of multlying the two sub-sequence items, for sub-array A[i...j] when the sub-sequence x starts at position i, and sub-sequence y ends on position j. 为了回答这个问题,我们首先将子序列x从位置i开始时,对于子数组A [i ... j],将S(i,j)定义为两个子序列项相乘的最大和,子序列y终止于位置j。

For example, if A=[1 7 4 0 9 4 0 1 8 8 2 4], then S(1, 2)=1*7=7 and S(2, 5)=7*9+4*0=63. 例如,如果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。

The recursive rule to compute S is: S(i, j)=max(0, S(i+1, j-1)+A[i]*A[j]), and the end condition is S(i, j)=0 iff i>=j. 计算S的递归规则为:S(i,j)= max(0,S(i + 1,j-1)+ A [i] * A [j]),结束条件为S(i, j)= 0,如果i> = j。

The requested final answer is simply the maximum value of S(i, j) for all combinations of i=1..N, j=1..N, since one of the S(i ,j) values will correspond to the max x,y sub-sequences, and thus will be equal the maximum value for the whole array. 对于i = 1..N,j = 1..N的所有组合,请求的最终答案只是S(i,j)的最大值,因为S(i,j)值之一将对应于最大值x,y子序列,因此将等于整个数组的最大值。 The complexity of computing all such S(i, j) values is O(N^2) using dynamic programming, since in the course of computing S(i, j) we will also compute the values of up to N other S(i', j') values, but ultimately each combination will be computed only once. 使用动态编程计算所有这些S(i,j)值的复杂度为O(N ^ 2),因为在计算S(i,j)的过程中,我们还将计算最多N个其他S(i)的值',j')值,但最终每个组合仅计算一次。

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

WARNING: This method assumes the numbers are non-negative so this solution does not answer the poster's actual problem now it has been clarified that negative input values are allowed. 警告:此方法假定数字为非负数,因此,现在已经弄清允许输入为负值,此解决方案无法解决海报的实际问题。

Trick 1 绝招1

Assuming the numbers are always non-negative, it is always best to make the sequences as wide as possible given the location where they meet. 假设数字始终为非负数,则在给定相遇的位置时,始终最好使序列尽可能宽。

Trick 2 把戏2

We can change the sum into a standard convolution by summing over all values of i. 通过对i的所有值求和,我们可以将和变成标准卷积。 This produces twice the desired result (as we get both the product of x with y, and y with x), but we can divide by 2 at the end to get the original answer. 这会产生两倍于预期结果的结果(因为我们同时得到x与y的乘积,以及y与x的乘积),但是我们可以在最后除以2得到原始答案。

Trick 3 绝招3

You are now attempting to find the maximum of a convolution of a signal with itself. 现在,您正在尝试寻找信号与其自身的卷积最大值。 There is a standard method for doing this which is to use the fast fourier transform. 有一种执行此操作的标准方法,即使用快速傅立叶变换。 Some libraries will have this built in, eg in Scipy there is fftconvolve . 一些库将内置此库,例如在Scipy中有fftconvolve

Python code Python代码

Note that you don't allow the central value to be reused (eg for a sequance 1,3,2 we can't make x 1,3 and y 3,1) so we need to examine alternate values of the convolved output. 请注意,您不允许重用中心值(例如,对于序列1,3,2,我们不能将x 1,3和y 3,1设为0),因此我们需要检查卷积输出的替代值。

We can now compute the answer in Python via: 我们现在可以通过以下方式在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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM