3

for example : A = [2, 3, 0, 1, 5]

Now A can be divided into multiple sub-arrays One way to do so is : A ~ [2], [3, 0], [1, 5]

Now the sum of absolute difference between max and min elements of all non overlapping sub-arrays that can be formed from an array is:

=> max([2]) - min([2]) + max([3, 0]) - min([3, 0]) + max([5, 1]) - min([5, 1]) 
=> 2 - 2 + 3 - 0 + 5 - 1
=> 7

Constraints for the Problem:

1 <= length of array <= 10^6

-10^9 <= A[i] <= 10^9

1 Answers1

2

We can have an O(n) dynamic program. Let's save three states per element:

1. best_sum_if_highest

2. best_sum_if_lowest

3. best_sum_if_neither

At each iteration, an element can (1) extend an earlier, lower or equal element's range if it was the highest of a section, (2) extend an earlier higher or equal element's range if it was the lowest of a section, or (3) not contribute to the overall sum.

Note that (1) and (2) are mutually exclusive since if the last different earlier element is higher, then the element cannot fulfill (1) and vice versa.

Let's assume that we merge sequences of more than two contiguous identical elements to a maximum of two because the extras cannot contribute.

Dynamic program:

// Extend lower highest
dp[i][0] = A[i] - A[i-1] + max(dp[i-1][0], dp[i-1][2])
  if A[i-1] ≤ A[i]
  
// Extend higher lowest
dp[i][1] = A[i-1] - A[i] + max(dp[i-1][1], dp[i-1][2])
  if A[i-1] ≥ A[i]
  
// Don't contribute
dp[i][2] = max(
  dp[i-1][0],
  dp[i-1][1],
  dp[i-1][2]
)

Example 1:

[2, 3, 0, 1, 5]

A[i]  states 
2     [0, 0, 0]
3     [1, 0, 0]
0     [0, 3, 1]
1     [2, 0, 3]
5     [7, 0, 3]

Example 2:

[1, 5, 2, 1, 6, 0, 7]

A[i]  states 
1     [0,  0,  0]
5     [4,  0,  0]
2     [0,  3,  4]
1     [0,  5,  4]
6     [9,  0,  5]
0     [0, 14,  9]
7     [16, 0, 14]

JavaScript code with random comparison against brute force (well, naive O(n^2) at any rate):

function f(A){
  const dp = new Array(A.length);
  
  for (let i=0; i<A.length; i++)
    dp[i] = [0, 0, 0];
  
  for (let i=1; i<A.length; i++){
    if (A[i] >= A[i-1]){
      dp[i][0] = A[i] - A[i-1] + Math.max(dp[i-1][0], dp[i-1][2]);
      dp[i][1] = 0;
    }
    
    if (A[i] <= A[i-1]){
      dp[i][0] = 0;
      dp[i][1] = A[i-1] - A[i] + Math.max(dp[i-1][1], dp[i-1][2]);
    }
    
    dp[i][2] = Math.max(...dp[i-1]);
  }
  
  return Math.max(...dp[A.length - 1]);
}


function bruteForce(A){
  const dp = new Array(A.length);
  
  dp[0] = 0;
  dp[-1] = 0;
  
  for (let i=1; i<A.length; i++){
    let min = A[i];
    let max = A[i];
    let best = dp[i-1];
    
    for (let j=i-1; j>=0; j--){
      min = Math.min(min, A[j]);
      max = Math.max(max, A[j]);
      best = Math.max(best, max - min + dp[j-1]);
    }
    
    dp[i] = best;
  }
  
  return dp[A.length - 1];
}

var numTests = 1000;

for (let i=0; i<numTests; i++){
  const N = 10;
  const A = [];
  const n = 50;
  for (let j=0; j<n; j++){
    const num = Math.floor(Math.random() * (1 << N));
    A.push(num);
  }

  const fA = f(A);
  const brute = bruteForce(A);

  if (fA != brute){
    console.log('Mismatch:');
    console.log(A);
    console.log(fA, brute);
    console.log('');
  }
}

console.log("Done testing.");
גלעד ברקן
  • 23,602
  • 3
  • 25
  • 61