Split into K subarrays to minimize the maximum sum of all subarrays (original) (raw)

Given an array **arr[] and a number **k, split the given array into **k subarrays such that the **maximum subarray sum achievable out of **k subarrays formed is the **minimum possible, find that possible subarray sum.

**Examples:

**Input: arr[] = [1, 2, 3, 4], k = 3
**Output: 4
**Explanation: Optimal Split is [1, 2], [3], [4]. Maximum sum of all subarrays is 4, which is minimum possible for 3 splits.

**Input: arr[] = [1, 1, 2], k = 2
**Output: 2
**Explanation: Splitting the array as [1, 1] and [2] is optimal. This results is a maximum sum subarray of 2.

Table of Content

**[Naive Approach] - By iterating through every possible solution

The idea is to recursively try all ways to split the array into k contiguous subarrays, tracking the maximum sum in each split. At each step, we pick a new partition point and update the current max sum. Once only one partition remains, the rest of the elements are grouped, and the overall minimum of the maximum subarray sums is recorded.

C++ `

#include
#include
#include
#include using namespace std;

void solve(vector &arr, int k, int index, int maxsum, int &ans) {

// K = 1 is the base Case
int n = arr.size();
int sum = 0;
if (k == 1) {

    for (int i = index; i < n; i++) {

        sum += arr[i];
    }
  
    // we update maxsum
    maxsum = max(maxsum, sum);

    ans = min(ans, maxsum);
    return;
}

// using for loop to divide the array into K-subarray
for (int i = index; i < n; i++) {

    sum += arr[i];
  
    // for each subarray we calculate sum ans update
    // maxsum
    maxsum = max(maxsum, sum);

    solve(arr, k - 1, i + 1, maxsum, ans);
}

}

int splitArray(vector &arr, int k) {

int ans = INT_MAX;
solve(arr, k, 0, 0, ans);
return ans;

} int main() {

vector<int> arr = {1, 2, 3, 4};
int k = 3;

cout << splitArray(arr, k);

}

Java

// Java code to iterate through // every possible solution import java.util.*;

class GfG { static void solve(int[] arr, int k, int index, int maxsum, int[] ans) {

    // K=1 is the base Case
    int n = arr.length;
    int sum = 0;
    if (k == 1) {
        for (int i = index; i < n; i++) {
            sum += arr[i];
        }
      
        // we update maxsum
        maxsum = Math.max(maxsum, sum);
      
        ans[0] = Math.min(ans[0], maxsum);
        return;
    }

    // using for loop to divide the array into
    // K-subarray
    for (int i = index; i < n; i++) {
        sum += arr[i];

        // for each subarray we calculate sum and update
        // maxsum
        maxsum = Math.max(maxsum, sum);

        solve(arr, k - 1, i + 1, maxsum, ans);
    }
}

static int splitArray(int[] arr, int k) {
    int[] ans = { Integer.MAX_VALUE };
    solve(arr, k, 0, 0, ans);
    return ans[0];
}

public static void main(String[] args) {
    int[] arr = { 1, 2, 3, 4 };
    int k = 3;

    System.out.println(splitArray(arr, k));
}

}

Python

Python code to iterate through

every possible solution

def solve(arr, k, index, maxsum, ans):

# K=1 is the base Case
n = len(arr)
sum = 0
if k == 1:
    for i in range(index, n):
        sum += arr[i]
        
    # we update maxsum
    maxsum = max(maxsum, sum)
    
    # the answer is stored in ans
    ans[0] = min(ans[0], maxsum)
    return

# using for loop to divide the array into K-subarray
for i in range(index, n):
    sum += arr[i]
    
    # for each subarray we calculate sum and update
    # maxsum
    maxsum = max(maxsum, sum)
    
    solve(arr, k - 1, i + 1, maxsum, ans)

def splitArray(arr, k): ans = [float('inf')] solve(arr, k, 0, 0, ans) return ans[0]

arr = [1, 2, 3, 4] k = 3

print(splitArray(arr, k))

C#

// C# code to iterate through // every possible solution using System;

class GfG { static void Solve(int[] arr, int k, int index, int maxsum, ref int ans) {

    // K=1 is the base Case
    int n = arr.Length;
    int sum = 0;
    if (k == 1) {
        for (int i = index; i < n; i++) {
            sum += arr[i];
        }
      
        // we update maxsum
        maxsum = Math.Max(maxsum, sum);
      
        ans = Math.Min(ans, maxsum);
        return;
    }

    // using for loop to divide the array into
    // K-subarray
    for (int i = index; i < n; i++) {
        sum += arr[i];
      
        // for each subarray we calculate sum and update
        // maxsum
        maxsum = Math.Max(maxsum, sum);
      
        Solve(arr, k - 1, i + 1, maxsum, ref ans);
    }
}

static int SplitArray(int[] arr, int k) {
    int ans = int.MaxValue;
    Solve(arr, k, 0, 0, ref ans);
    return ans;
}

static void Main(string[] args) {
    int[] arr = { 1, 2, 3, 4 };
    int k = 3;

    Console.WriteLine(SplitArray(arr, k));
}

}

JavaScript

function solve(arr, k, index, maxsum, ans) {

// K=1 is the base Case
const n = arr.length;
let sum = 0;
if (k === 1) {
    for (let i = index; i < n; i++) {
        sum += arr[i];
    }
    
    // we update maxsum
    maxsum = Math.max(maxsum, sum);

    ans[0] = Math.min(ans[0], maxsum);
    return;
}

// using for loop to divide the array into K-subarray
for (let i = index; i < n; i++) {
    sum += arr[i];
    
    // for each subarray we calculate sum and update
    // maxsum
    maxsum = Math.max(maxsum, sum);

    solve(arr, k - 1, i + 1, maxsum, ans);
}

}

function splitArray(arr, k) { let ans = [ Infinity ]; solve(arr, k, 0, 0, ans); return ans[0]; }

// Driver Code const arr = [ 1, 2, 3, 4 ]; const k = 3;

console.log(splitArray(arr, k));

`

**Time Complexity: O((n-1)C(k-1)), to explores all ways to split n elements into k contiguous parts by choosing k-1 split points from n-1 possible positions.
**Auxiliary Space: O(k), due to the maximum recursion depth being k, with each call using constant space.

The approach uses Binary Search to find the minimum possible value for the maximum subarray sum when the array is split into k subarrays. The binary search range is between the maximum element of the array (since no subarray can have a sum less than the largest element) and the total sum of the array (which is the maximum sum when the entire array is considered as a single subarray). For each **midpoint value, we check if it's possible to split the array into k or fewer subarrays such that no subarray's sum exceeds the midpoint. If it is possible, we attempt to **minimize the maximum sum by narrowing the search range to smaller values.

C++ `

#include
#include
#include using namespace std;

bool check(int mid, vector &arr, int k) {

int n = arr.size();
int count = 0;
int sum = 0;
for (int i = 0; i < n; i++) {

    // If individual element is greater
    // maximum possible sum
    if (arr[i] > mid)
        return false;

    // Increase sum of current sub - arr
    sum += arr[i];

    // If the sum is greater than
    // mid increase count
    if (sum > mid) {

        count++;
        sum = arr[i];
    }
}
count++;

if (count <= k)
    return true;
return false;

}

int splitArray(vector &arr, int k) {

int n = arr.size();
int max = *max_element(arr.begin(), arr.end());

// Max subarr sum, considering subarr of length 1
int start = max;

// Max subarr sum, considering subarr of length n
int end = 0;

for (int i = 0; i < n; i++) {

    end += arr[i];
}

// ans stores possible
// maximum sub arr sum
int ans = 0;
while (start <= end) {

    int mid = (start + end) / 2;

    // If mid is possible solution
    // Put ans = mid;
    if (check(mid, arr, k)) {

        ans = mid;
        end = mid - 1;
    }
    else {
        start = mid + 1;
    }
}

return ans;

}

int main() {

vector<int> arr = {1, 2, 3, 4};
int k = 3;
cout << splitArray(arr, k);

}

Java

import java.util.*;

class GfG {

static boolean check(int mid, int[] arr, int k) {
    int n = arr.length;
    int count = 0;
    int sum = 0;
    for (int i = 0; i < n; i++) {
      
        // If individual element is greater
        // maximum possible sum
        if (arr[i] > mid)
            return false;

        // Increase sum of current sub - arr
        sum += arr[i];

        // If the sum is greater than
        // mid increase count
        if (sum > mid) {
            count++;
            sum = arr[i];
        }
    }
    count++;

    return count <= k;
}

static int splitArray(int[] arr, int k) {
    int n = arr.length;
    int max = Arrays.stream(arr).max().getAsInt();

    // Max subarr sum, considering subarr of length 1
    int start = max;

    // Max subarr sum, considering subarr of length n
    int end = 0;

    for (int value : arr) {
        end += value;
    }

    // ans stores possible
    // maximum sub arr sum
    int ans = 0;
    while (start <= end) {
        int mid = (start + end) / 2;

        // If mid is possible solution
        // Put ans = mid;
        if (check(mid, arr, k)) {
            ans = mid;
            end = mid - 1;
        }
        else {
            start = mid + 1;
        }
    }

    return ans;
}

public static void main(String[] args) {
    int[] arr = { 1, 2, 3, 4 };
    int k = 3;
    System.out.println(splitArray(arr, k));
}

}

Python

def check(mid, arr, k): n = len(arr) count = 0 total = 0 for num in arr:

    # If individual element is greater
    # maximum possible sum
    if num > mid:
        return False

    # Increase sum of current sub-array
    total += num

    # If the sum is greater than mid, increase count
    if total > mid:
        count += 1
        total = num
count += 1

return count <= k

def splitArray(arr, k): n = len(arr) start = max(arr) end = sum(arr)

# ans stores possible maximum subarray sum
ans = 0
while start <= end:
    mid = (start + end) // 2

    # If mid is possible solution, set ans = mid
    if check(mid, arr, k):
        ans = mid
        end = mid - 1
    else:
        start = mid + 1

return ans

arr = [1, 2, 3, 4] k = 3 print(splitArray(arr, k))

C#

using System; using System.Linq;

class GfG {

static bool Check(int mid, int[] arr, int k) {
    int n = arr.Length;
    int count = 0;
    int sum = 0;
    for (int i = 0; i < n; i++) {
      
        // If individual element is greater
        // maximum possible sum
        if (arr[i] > mid)
            return false;

        // Increase sum of current sub-array
        sum += arr[i];

        // If the sum is greater than mid, increase
        // count
        if (sum > mid) {
            count++;
            sum = arr[i];
        }
    }
    count++;
  
    return count <= k;
}

static int SplitArray(int[] arr, int k) {
    int n = arr.Length;
    int start = arr.Max();
    int end = 0;

    foreach(int num in arr) { end += num; }

    // ans stores possible maximum subarray sum
    int ans = 0;
    while (start <= end) {
        int mid = (start + end) / 2;

        // If mid is possible solution, set ans = mid
        if (Check(mid, arr, k)) {
            ans = mid;
            end = mid - 1;
        }
        else {
            start = mid + 1;
        }
    }

    return ans;
}

static void Main() {
    int[] arr = { 1, 2, 3, 4 };
    int k = 3;

    Console.WriteLine(SplitArray(arr, k));
}

}

JavaScript

function check(mid, arr, k) { const n = arr.length; let count = 0; let sum = 0;

for (let i = 0; i < n; i++) {

    // If individual element is greater
    // maximum possible sum
    if (arr[i] > mid) {
        return false;
    }

    // Increase sum of current sub-array
    sum += arr[i];

    // If the sum is greater than mid, increase count
    if (sum > mid) {
        count++;
        sum = arr[i];
    }
}
count++;

return count <= k;

}

function splitArray(arr, k) {

const n = arr.length;
let start
    = Math.max(...arr);
let end
    = arr.reduce((a, b) => a + b,
                 0);

// ans stores possible maximum subarray sum
let ans = 0;
while (start <= end) {
    const mid = Math.floor((start + end) / 2);

    // If mid is possible solution, set ans = mid
    if (check(mid, arr, k)) {
        ans = mid;
        end = mid - 1;
    }
    else {
        start = mid + 1;
    }
}

return ans;

}

// Driver Code const arr = [ 1, 2, 3, 4 ]; const k = 3;

console.log(splitArray(arr, k));

`

**Time Complexity: O(n * log(sum)), where n is the array size and sum is the total sum of the array, due to binary search from max(arr) to sum(arr) and linear checking in each iteration.
**Auxiliary Space: O(1), uses constant extra space regardless of input size (excluding input and output storage).