Split into K subarrays to minimize the maximum sum of all subarrays
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. The task is to 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 – O(nCk) Time and O(k) Space
To explore all possibilities, we use backtracking. At each step, the array is divided into subarrays, and the sum of each subarray is calculated.
// C++ code to iterate through
// every possible solution
#include <bits/stdc++.h>
using namespace std;
void solve(vector<int> &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<int> &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 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 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# 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 code to iterate through
// every possible solution
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));
Output
4
Time Complexity: O((n-1)C(k-1))
(Note: ‘c’ here depicts combinations i.e. ((n-1)!/((n-k)!*(k-1)!), where n is the number of elements of the array and k is the number of divisions.
Auxiliary Space: O(k)
[Expected Approach] – Using Binary Search – O(n*log(sum)) Time and O(1) 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++ code to solve above problem
// using binary search
#include <bits/stdc++.h>
using namespace std;
bool check(int mid, vector<int> &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<int> &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 code to solve above problem
// using binary search
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 code to solve above problem
# using binary search
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# code to solve above problem
// using binary search
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 code to solve above problem
// using binary search
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));
Output
4