哈克兰克的夏洛克和成本

时间:2018-02-16 20:51:51

标签: recursion dynamic-programming

关于this 动态编程挑战。

如果您很难理解问题,请参阅 AbhishekVermaIIT ' post

基本上,你得到一个数组B作为输入,你构造了数组A.对于这个数组A,absolute(A[i] - A[i-1])需要{strong>最大可能总和和i = 1 to N。如何构造数组A? - >您可以为数组A[i]中的每个元素A选择值1B[i]。 (正如您将从问题描述中推断出这两个值之间的任何其他值都没有任何意义。)

我想出了这个递归Java解决方案(没有memoization):

static int costHelper(int[] arr, int i) {
  if (i < 1) return 0;

  int q = max(abs(1 - arr[i-1]) + costHelper(arr, i-1) , abs(arr[i] - arr[i-1]) + costHelper(arr, i-1));

  int[] arr1 = new int[i];
  for (int j = 0; j < arr1.length-1; j++) {
    arr1[j] = arr[j];
  }
  arr1[i-1] = 1;
  int r = max(abs(1 - 1) + costHelper(arr1, i-1) , abs(arr[i] - 1) + costHelper(arr1, i-1));

  return max(q , r);
}


static int cost(int[] arr) {
  return costHelper(arr, arr.length-1);
}


public static void main(String[] args) {
  int[] arr = {55, 68, 31, 80, 57, 18, 34, 28, 76, 55};
  int result = cost(arr);
  System.out.println(result);
}

基本上,我从数组的末尾开始,检查最大化last element减去last element - 1之和的内容。但我有4个案例:

  1. (1 - arr[i-1])
  2. (arr[i] - arr[i-1])
  3. (1 - 1) // I know, it is not necessary.
  4. (arr[i] -1)
  5. 对于第3或第4种情况,我构造了一个新数组,一个元素的大小小于输入数组,并且1作为最后一个元素。

    现在,根据Hackerrank的arr = 55 68 31 80 57 18 34 28 76 55结果应为508.但我得到了564。

    因为它必须是508,我猜数组应该是1 68 1 80 1 1 34 1 76 1

    对于其他阵列,我得到了正确的答案。例如:

    79 6 40 68 68 16 40 63 93 49 91 --> 642 (OK)
    
    100 2 100 2 100 --> 396 (OK)
    

    我不明白这个算法有什么问题。

3 个答案:

答案 0 :(得分:1)

我不确定您的特定解决方案究竟发生了什么,但我怀疑递归函数可能只有一个维度i,因为我们需要一种方法来识别最佳先前解决方案f(i-1),如果选择了B_(i-1)并且此时选择了1,那么我们可以选择最适合f(i)的{​​{1}} 。 (如果您可以用单词添加算法描述,可能会有所帮助。)

让我们看看蛮力动态程序:当m[i][j1]A[0..i]时,让A_i代表j1中最佳的abs-diff差异}。然后,一般来说:

m[i][j1] = max(abs(j1 - j0) + m[i-1][j0])
  for j0 in [1..B_(i-1)] and j1 in [1..B_i] 

Python代码:

def cost(arr):
  if len(arr) == 1:
    return 0

  m = [[float('-inf')]*101 for i in xrange(len(arr))]

  for i in xrange(1, len(arr)):
    for j0 in xrange(1, arr[i-1] + 1):
      for j1 in xrange(1, arr[i] + 1):
        m[i][j1] = max(m[i][j1], abs(j1 - j0) + (m[i-1][j0] if i > 1 else 0))

  return max(m[len(arr) - 1])

由于我们循环可能100 * 100 * 10 ^ 5次迭代,因此可以工作但是超时。

我还没有考虑过它的证明,但是,正如你的建议,显然我们只能为每个1选择B_iA_i以获得最佳效果解。这使我们可以直接在一个非常有效的解决方案中进行选择,而这种解决方案不会超时:

def cost(arr):
  if len(arr) == 1:
    return 0

  m = [[float('-inf')]*2 for i in xrange(len(arr))]

  for i in xrange(1, len(arr)):
    for j0 in [1, arr[i-1]]:
      for j1 in [1, arr[i]]:
        a_i = 0 if j1 == 1 else 1
        b_i = 0 if j0 == 1 else 1

        m[i][a_i] = max(m[i][a_i], abs(j1 - j0) + (m[i-1][b_i] if i > 1 else 0))

  return max(m[len(arr) - 1])

这是一个自下而上的制表,但我们可以使用相同的想法轻松将其转换为递归制表。

答案 1 :(得分:0)

这是带有备注的javascript代码-

function cost(B,n,val) {
    if(n==-1){
        return 0;
    }
    let prev1=0,prev2=0;
    if(n!=0){
        if(dp[n-1][0]==-1)
            dp[n-1][0] = cost(B,n-1,1);        
        if(dp[n-1][1]==-1)
            dp[n-1][1] = cost(B,n-1,B[n]);
        prev1=dp[n-1][0];
        prev2=dp[n-1][1];
    }
    prev1 = prev1 + Math.abs(val-1);
    prev2 = prev2+ Math.abs(val-B[n]);
    return Math.max(prev1,prev2);
}

其中B->给定数组,n->总长度,val-> 1或B [n],是调用函数考虑的值。

初始调用-> Math.max(cost(B,n-2,1),cost(B,n-2,B [n-1]));

顺便说一句,这花了我大约3个小时,而使用迭代方法可以轻松完成。 :p

答案 2 :(得分:0)

           //dp[][0] is when a[i]=b[i]
       dp[i][0]=max((dp[i-1][0]+abs(b[i]-b[i-1])),(dp[i-1][1]+abs(b[i]-1)));
       dp[i][1]=max((dp[i-1][1]+abs(1-1)),(dp[i-1][0]+abs(b[i-1]-1)));

最初dp中的所有元素的值均为0。 我们知道,如果任何i的值都是b [i]或1,我们都会得到答案。因此最终答案是:

max(dp[n-1][0],dp[n-1][1])

dp [i] [0]表示a [i] = b [i],dp [i] [1]表示a [i] = 1。 因此,在每个i处,我们都希望[i-1] [0](上一个元素为b [i-1])或[i-1] [1](上一个元素为1)的最大值