Given an array nums which consists of non-negative integers and an integer m
,
you can split the array into m
non-empty continuous subarrays.
Write an algorithm to minimize the largest sum among these m
subarrays.
How to Solve
- Fill the array
prefixSum
. The ith index ofprefixSum
will have the sum of integers in nums in the range[0, i - 1]
withprefix[0] = 0
. - Initialize an array memo where
memo[currIndex][subarrayCount]
will store the result for the subproblem(currIndex, subarrayCount)
. - We need to find the value of
memo[0][m]
which represents the minimum largest subarray sum starting at index0
withm
subarrays.- But we only know what the result will be for the base cases.
- To fill the memo array, we will iterate subarrayCount over the range
[1, m]
(starting at1
because that is our base case) and iteratecurrIndex
over the range[0, n - 1]
.
- For each value of
subarrayCount
andcurrIndex
, we will updatememo[subarrayCount][currIndex]
:- As the sum of the elements between
currIndex
and the end of the array if we are at a base case (subarrayCount
equals 1). - Otherwise, we will use the recurrence relation and the results from previously solved subproblems to calculate
memo[subarrayCount][currIndex]
.
- As the sum of the elements between
- Return the value stored at
memo[0][m]
.
Test Cases
Example 1:
Input: nums = [7,2,5,10,8], m = 2
Output: 18
Explanation:
There are four ways to split nums into two subarrays.
The best way is to split it into [7,2,5] and [10,8],
where the largest sum among the two subarrays is only 18.
Example 2:
Input: nums = [1,2,3,4,5], m = 2
Output: 9
Example 3:
Input: nums = [1,4,4], m = 3
Output: 4
Solution
class Solution {
public int splitArray(int[] nums, int m) {
int n = nums.length;
int[][] memo = new int[n+1][m+1];
int[] prefixSum = new int[n + 1];
for (int i = 0; i < n; i++) {
prefixSum[i + 1] = prefixSum[i] + nums[i];
}
for (int subarrayCount = 1; subarrayCount <= m; subarrayCount++) {
for (int currIndex = 0; currIndex < n; currIndex++) {
if (subarrayCount == 1) {
memo[currIndex][subarrayCount] = prefixSum[n] - prefixSum[currIndex];
continue;
}
int minimumLargestSplitSum = Integer.MAX_VALUE;
for (int i = currIndex; i <= n - subarrayCount; i++) {
int firstSplitSum = prefixSum[i + 1] - prefixSum[currIndex];
int largestSplitSum = Math.max(firstSplitSum, memo[i + 1][subarrayCount - 1]);
minimumLargestSplitSum = Math.min(minimumLargestSplitSum, largestSplitSum);
if (firstSplitSum >= minimumLargestSplitSum) {
break;
}
}
memo[currIndex][subarrayCount] = minimumLargestSplitSum;
}
}
return memo[0][m];
}
}