Given an array arr[] of integers, find two non-overlapping contiguous sub-arrays such that the absolute difference between the sum of the two sub-arrays is maximum.
Examples:
Input: arr[] = {-2, -3, 4, -1, -2, 1, 5, -3}
Output: 12
Explanation: One possible pair of non-overlapping subarrays is: {-2, -3} and {4, -1, -2, 1, 5}. Their sums are -5 and 7 respectively, so the absolute difference is: |(-5) - 7| = 12Input: arr[] = {2, -1, -2, 1, -4, 2, 8}
Output: 16
Explanation: One possible pair of non-overlapping subarrays is:{-1, -2, 1, -4} and {2, 8}. Their sums are -6 and 10 respectively, so the absolute difference is: |(-6) - 10| = 16
Table of Content
[Naive Approach] Try All Subarray Pairs - O(n4) Time and O(1) Space
The idea of this approach is to generate every possible contiguous subarray and compare it with every other contiguous subarray that does not overlap with it.
For each valid pair, calculate the sum of both subarrays and update the maximum absolute difference.
#include <cmath>
#include <iostream>
using namespace std;
int findMaxAbsDiff(int arr[], int n)
{
int result = 0;
// Generate first subarray
for (int i = 0; i < n; i++)
{
int sum1 = 0;
for (int j = i; j < n; j++)
{
sum1 += arr[j];
// Generate second subarray
for (int l = 0; l < n; l++)
{
int sum2 = 0;
for (int r = l; r < n; r++)
{
sum2 += arr[r];
// Check if both subarrays are non-overlapping
if (r < i || l > j)
{
// Update the maximum absolute difference
result = max(result, abs(sum1 - sum2));
}
}
}
}
}
return result;
}
int main()
{
int arr[] = {-2, -3, 4, -1, -2, 1, 5, -3};
int n = sizeof(arr) / sizeof(arr[0]);
cout << findMaxAbsDiff(arr, n);
return 0;
}
import java.util.Arrays;
public class Main {
public static int findMaxAbsDiff(int[] arr, int n) {
int result = 0;
// Generate first subarray
for (int i = 0; i < n; i++) {
int sum1 = 0;
for (int j = i; j < n; j++) {
sum1 += arr[j];
// Generate second subarray
for (int l = 0; l < n; l++) {
int sum2 = 0;
for (int r = l; r < n; r++) {
sum2 += arr[r];
// Check if both subarrays are non-overlapping
if (r < i || l > j) {
// Update the maximum absolute difference
result = Math.max(result, Math.abs(sum1 - sum2));
}
}
}
}
}
return result;
}
public static void main(String[] args) {
int[] arr = {-2, -3, 4, -1, -2, 1, 5, -3};
int n = arr.length;
System.out.println(findMaxAbsDiff(arr, n));
}
}
def findMaxAbsDiff(arr, n):
result = 0
# Generate first subarray
for i in range(n):
sum1 = 0
for j in range(i, n):
sum1 += arr[j]
# Generate second subarray
for l in range(n):
sum2 = 0
for r in range(l, n):
sum2 += arr[r]
# Check if both subarrays are non-overlapping
if r < i or l > j:
# Update the maximum absolute difference
result = max(result, abs(sum1 - sum2))
return result
if __name__ == '__main__':
arr = [-2, -3, 4, -1, -2, 1, 5, -3]
n = len(arr)
print(findMaxAbsDiff(arr, n))
using System;
public class Program {
public static int findMaxAbsDiff(int[] arr, int n) {
int result = 0;
// Generate first subarray
for (int i = 0; i < n; i++) {
int sum1 = 0;
for (int j = i; j < n; j++) {
sum1 += arr[j];
// Generate second subarray
for (int l = 0; l < n; l++) {
int sum2 = 0;
for (int r = l; r < n; r++) {
sum2 += arr[r];
// Check if both subarrays are non-overlapping
if (r < i || l > j) {
// Update the maximum absolute difference
result = Math.Max(result, Math.Abs(sum1 - sum2));
}
}
}
}
}
return result;
}
public static void Main() {
int[] arr = {-2, -3, 4, -1, -2, 1, 5, -3};
int n = arr.Length;
Console.WriteLine(findMaxAbsDiff(arr, n));
}
}
function findMaxAbsDiff(arr, n) {
let result = 0;
// Generate first subarray
for (let i = 0; i < n; i++) {
let sum1 = 0;
for (let j = i; j < n; j++) {
sum1 += arr[j];
// Generate second subarray
for (let l = 0; l < n; l++) {
let sum2 = 0;
for (let r = l; r < n; r++) {
sum2 += arr[r];
// Check if both subarrays are non-overlapping
if (r < i || l > j) {
// Update the maximum absolute difference
result = Math.max(result, Math.abs(sum1 - sum2));
}
}
}
}
}
return result;
}
let arr = [-2, -3, 4, -1, -2, 1, 5, -3];
let n = arr.length;
console.log(findMaxAbsDiff(arr, n));
Output
12
[Expected Approach] Left and Right Max and Min Arrays - O(n) Time and O(n) Space
The idea of this approach is to split the array at every possible position and find the maximum absolute difference between a subarray on the left side and a subarray on the right side.
To maximize the absolute difference, we only need to consider:
- The maximum subarray sum on one side and the minimum subarray sum on the other side.
- The minimum subarray sum on one side and the maximum subarray sum on the other side.
For every index
i, we maintain 4 values:
- leftmax[i] = Maximum subarray sum in arr[0...i],
- leftmin[i] = Minimum subarray sum in arr[0...i],
- rightmax[i] = Maximum subarray sum in arr[i...n-1]
- rightmin[i] = Minimum subarray sum in arr[i...n-1].
These arrays can be built in O(n) time using Kadane's Algorithm. The answer for every partition after index
iis obtained using: abs(leftmax[i] - rightmin[i + 1]) or abs(leftmin[i] - rightmax[i + 1])
Taking the maximum value over all partition points gives the final answer.
Consider: arr[] = [-2, -3, 4, -1, -2, 1, 5, -3]
After preprocessing,
- leftmax[] = {-2, -2, 4, 4, 4, 4, 7, 7}
- leftmin[] = {-2, -5, -5, -5, -5, -5, -5, -5}
- rightmax[] = {7, 7, 7, 6, 6, 6, 5, -3}
- rightmin[] = {-5, -3, -3, -3, -3, -3, -3, -3}.
Now consider the partition after index 1: Left part = {-2, -3} and Right part = {4, -1, -2, 1, 5, -3}
Compute the two possible answers:
abs(leftmax[1] - rightmin[2]) = abs(-2 - (-3)) = 1
abs(leftmin[1] - rightmax[2]) = abs(-5 - 7) = 12
So the best answer for this partition is: 12. Checking all partition points gives the maximum absolute difference as: 12
#include <iostream>
#include <vector>
#include <climits>
#include <cmath>
using namespace std;
// Store maximum subarray sum in arr[0...i]
void buildleftmax(vector<int>& arr, vector<int>& leftmax) {
int currmax = arr[0];
int maxsofar = arr[0];
leftmax[0] = arr[0];
for (int i = 1; i < arr.size(); i++) {
currmax = max(arr[i], currmax + arr[i]);
maxsofar = max(maxsofar, currmax);
leftmax[i] = maxsofar;
}
}
// Store maximum subarray sum in arr[i...n-1]
void buildrightmax(vector<int>& arr, vector<int>& rightmax) {
int n = arr.size();
int currmax = arr[n - 1];
int maxsofar = arr[n - 1];
rightmax[n - 1] = arr[n - 1];
for (int i = n - 2; i >= 0; i--) {
currmax = max(arr[i], currmax + arr[i]);
maxsofar = max(maxsofar, currmax);
rightmax[i] = maxsofar;
}
}
int findmaxabsdiff(vector<int>& arr) {
int n = arr.size();
vector<int> leftmax(n);
vector<int> rightmax(n);
vector<int> leftmin(n);
vector<int> rightmin(n);
buildleftmax(arr, leftmax);
buildrightmax(arr, rightmax);
vector<int> invertarr(n);
// Invert array to obtain minimum subarray sums
for (int i = 0; i < n; i++) {
invertarr[i] = -arr[i];
}
buildleftmax(invertarr, leftmin);
buildrightmax(invertarr, rightmin);
for (int i = 0; i < n; i++) {
leftmin[i] = -leftmin[i];
rightmin[i] = -rightmin[i];
}
int result = INT_MIN;
// Check every partition point
for (int i = 0; i < n - 1; i++) {
result = max(result,
abs(leftmax[i] - rightmin[i + 1]));
result = max(result,
abs(leftmin[i] - rightmax[i + 1]));
}
return result;
}
int main() {
vector<int> arr = {-2, -3, 4, -1, -2, 1, 5, -3};
cout << findmaxabsdiff(arr);
return 0;
}
public class GFG {
// Store maximum subarray sum in arr[0...i]
static void buildleftmax(int[] arr, int[] leftmax) {
int currmax = arr[0];
int maxsofar = arr[0];
leftmax[0] = arr[0];
for (int i = 1; i < arr.length; i++) {
currmax = Math.max(arr[i], currmax + arr[i]);
maxsofar = Math.max(maxsofar, currmax);
leftmax[i] = maxsofar;
}
}
// Store maximum subarray sum in arr[i...n-1]
static void buildrightmax(int[] arr, int[] rightmax) {
int n = arr.length;
int currmax = arr[n - 1];
int maxsofar = arr[n - 1];
rightmax[n - 1] = arr[n - 1];
for (int i = n - 2; i >= 0; i--) {
currmax = Math.max(arr[i], currmax + arr[i]);
maxsofar = Math.max(maxsofar, currmax);
rightmax[i] = maxsofar;
}
}
static int findmaxabsdiff(int[] arr) {
int n = arr.length;
int[] leftmax = new int[n];
int[] rightmax = new int[n];
int[] leftmin = new int[n];
int[] rightmin = new int[n];
buildleftmax(arr, leftmax);
buildrightmax(arr, rightmax);
int[] invertarr = new int[n];
// Invert array to obtain minimum subarray sums
for (int i = 0; i < n; i++) {
invertarr[i] = -arr[i];
}
buildleftmax(invertarr, leftmin);
buildrightmax(invertarr, rightmin);
for (int i = 0; i < n; i++) {
leftmin[i] = -leftmin[i];
rightmin[i] = -rightmin[i];
}
int result = Integer.MIN_VALUE;
// Check every partition point
for (int i = 0; i < n - 1; i++) {
result = Math.max(result,
Math.abs(leftmax[i] - rightmin[i + 1]));
result = Math.max(result,
Math.abs(leftmin[i] - rightmax[i + 1]));
}
return result;
}
public static void main(String[] args) {
int[] arr = {-2, -3, 4, -1, -2, 1, 5, -3};
System.out.println(findmaxabsdiff(arr));
}
}
# Store maximum subarray sum in arr[0...i]
def buildleftmax(arr):
leftmax = [0] * len(arr)
currmax = arr[0]
maxsofar = arr[0]
leftmax[0] = arr[0]
for i in range(1, len(arr)):
currmax = max(arr[i], currmax + arr[i])
maxsofar = max(maxsofar, currmax)
leftmax[i] = maxsofar
return leftmax
# Store maximum subarray sum in arr[i...n-1]
def buildrightmax(arr):
n = len(arr)
rightmax = [0] * n
currmax = arr[n - 1]
maxsofar = arr[n - 1]
rightmax[n - 1] = arr[n - 1]
for i in range(n - 2, -1, -1):
currmax = max(arr[i], currmax + arr[i])
maxsofar = max(maxsofar, currmax)
rightmax[i] = maxsofar
return rightmax
def findmaxabsdiff(arr):
leftmax = buildleftmax(arr)
rightmax = buildrightmax(arr)
# Invert array to obtain minimum subarray sums
invertarr = [-x for x in arr]
leftmin = buildleftmax(invertarr)
rightmin = buildrightmax(invertarr)
leftmin = [-x for x in leftmin]
rightmin = [-x for x in rightmin]
result = float("-inf")
# Check every partition point
for i in range(len(arr) - 1):
result = max(
result,
abs(leftmax[i] - rightmin[i + 1])
)
result = max(
result,
abs(leftmin[i] - rightmax[i + 1])
)
return result
arr = [-2, -3, 4, -1, -2, 1, 5, -3]
print(findmaxabsdiff(arr))
using System;
class GFG
{
// Store maximum subarray sum in arr[0...i]
static void buildleftmax(int[] arr, int[] leftmax)
{
int currmax = arr[0];
int maxsofar = arr[0];
leftmax[0] = arr[0];
for (int i = 1; i < arr.Length; i++)
{
currmax = Math.Max(arr[i], currmax + arr[i]);
maxsofar = Math.Max(maxsofar, currmax);
leftmax[i] = maxsofar;
}
}
// Store maximum subarray sum in arr[i...n-1]
static void buildrightmax(int[] arr, int[] rightmax)
{
int n = arr.Length;
int currmax = arr[n - 1];
int maxsofar = arr[n - 1];
rightmax[n - 1] = arr[n - 1];
for (int i = n - 2; i >= 0; i--)
{
currmax = Math.Max(arr[i], currmax + arr[i]);
maxsofar = Math.Max(maxsofar, currmax);
rightmax[i] = maxsofar;
}
}
static int findmaxabsdiff(int[] arr)
{
int n = arr.Length;
int[] leftmax = new int[n];
int[] rightmax = new int[n];
int[] leftmin = new int[n];
int[] rightmin = new int[n];
buildleftmax(arr, leftmax);
buildrightmax(arr, rightmax);
int[] invertarr = new int[n];
// Invert array to obtain minimum subarray sums
for (int i = 0; i < n; i++)
{
invertarr[i] = -arr[i];
}
buildleftmax(invertarr, leftmin);
buildrightmax(invertarr, rightmin);
for (int i = 0; i < n; i++)
{
leftmin[i] = -leftmin[i];
rightmin[i] = -rightmin[i];
}
int result = int.MinValue;
// Check every partition point
for (int i = 0; i < n - 1; i++)
{
result = Math.Max(
result,
Math.Abs(leftmax[i] - rightmin[i + 1]));
result = Math.Max(
result,
Math.Abs(leftmin[i] - rightmax[i + 1]));
}
return result;
}
static void Main()
{
int[] arr = {-2, -3, 4, -1, -2, 1, 5, -3};
Console.WriteLine(findmaxabsdiff(arr));
}
}
// Store maximum subarray sum in arr[0...i]
function buildleftmax(arr) {
let leftmax = new Array(arr.length);
let currmax = arr[0];
let maxsofar = arr[0];
leftmax[0] = arr[0];
for (let i = 1; i < arr.length; i++) {
currmax = Math.max(arr[i], currmax + arr[i]);
maxsofar = Math.max(maxsofar, currmax);
leftmax[i] = maxsofar;
}
return leftmax;
}
// Store maximum subarray sum in arr[i...n-1]
function buildrightmax(arr) {
let n = arr.length;
let rightmax = new Array(n);
let currmax = arr[n - 1];
let maxsofar = arr[n - 1];
rightmax[n - 1] = arr[n - 1];
for (let i = n - 2; i >= 0; i--) {
currmax = Math.max(arr[i], currmax + arr[i]);
maxsofar = Math.max(maxsofar, currmax);
rightmax[i] = maxsofar;
}
return rightmax;
}
function findmaxabsdiff(arr) {
let leftmax = buildleftmax(arr);
let rightmax = buildrightmax(arr);
// Invert array to obtain minimum subarray sums
let invertarr = arr.map(x => -x);
let leftmin = buildleftmax(invertarr);
let rightmin = buildrightmax(invertarr);
leftmin = leftmin.map(x => -x);
rightmin = rightmin.map(x => -x);
let result = Number.MIN_SAFE_INTEGER;
// Check every partition point
for (let i = 0; i < arr.length - 1; i++) {
result = Math.max(
result,
Math.abs(leftmax[i] - rightmin[i + 1])
);
result = Math.max(
result,
Math.abs(leftmin[i] - rightmax[i + 1])
);
}
return result;
}
let arr = [-2, -3, 4, -1, -2, 1, 5, -3];
console.log(findmaxabsdiff(arr));
Output
12