package com.freetymekiyan.algorithms.level.hard;
/**
* Given an array 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.
* <p>
* Note:
* Given m satisfies the following constraint: 1 ≤ m ≤ length(nums) ≤ 14,000.
* <p>
* Examples:
* <p>
* Input:
* nums = [7,2,5,10,8]
* m = 2
* <p>
* Output:
* 18
* <p>
* 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.
* <p>
* Company Tags: Baidu, Facebook
* Tags: Binary Search, Dynamic Programming
*/
public class SplitArrayLargestSum {
/**
* Binary Search.
* The max of the result is the sum of all the input numbers.
* The min of the result is the max num of the input numbers.
* Given a result, validate it by checking whether it generates m cuts.
* Given the 3 conditions above we can do a binary search.
* Use long for range to avoid overflow since it's sum of array.
*/
public int splitArray(int[] nums, int m) {
// Find sum and max.
long sum = 0; // May overflow.
int max = 0;
for (int n : nums) {
sum += n;
max = Math.max(max, n);
}
// Binary search the minimum sum limit.
long lo = max;
long hi = sum;
while (lo < hi) {
long mid = lo + (hi - lo) / 2;
if (validate(nums, mid, m)) {
hi = mid;
} else {
lo = mid + 1;
}
}
return (int) lo; // Convert long to int.
}
/**
* Validate whether given the max exceeds m subarrays.
* If it needs more than m, return false. Otherwise return true.
* Use an integer sum for current subarray sum.
* Use an integer count for the # of subarrays.
* For each number n in nums:
* | Update sum to sum + n.
* | If sum > max:
* | sum = n
* | count++
* | If count > m, return false.
* Return true.
*/
private boolean validate(int[] nums, long max, int m) {
int sum = 0;
int count = 1; // IMPORTANT! Already have 1 array.
for (int n : nums) {
sum += n;
if (sum > max) {
sum = n;
count++;
if (count > m) {
return false;
}
}
}
return true;
}
}