# leetcode410. Split Array Largest Sum

## 题目要求

``````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.

Note:
If n is the length of array, assume the following constraints are satisfied:

1 ≤ n ≤ 1000
1 ≤ m ≤ min(50, n)
Examples:

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.
``````

1. [7], [2,5,10,8]
2. [7,2], [5,8,10]
3. [7,2,5], [8,10]
4. [7,2,5,8], [10]

## 思路一：动态规划

``````    public int splitArray(int[] nums, int m) {
//计算[0...i]中所有元素的和
int[] sums = new int[nums.length+1];
for(int i = 1 ; i<=nums.length ; i++) {
sums[i] = nums[i-1] + sums[i-1];
}
return splitArray(nums, m, 0, sums);
}

//计算从cur位置开始，将其分割为m个子数组的最小分割场景
public int splitArray(int[] nums, int m, int cur, int[] sums) {
if(m == 1) {
return sums[nums.length] - sums[cur];
}
int min = Integer.MAX_VALUE;
int diff = Integer.MAX_VALUE;
for(int i = cur+1 ; i<=nums.length-m+1 ; i++) {
//当前元素为止，左边的子数组的元素和
int left = sums[i]-sums[cur];
//对右边的剩余元素递归的调用splitArray方法
int right = splitArray(nums, m-1, i, sums);
//如果出现二者之间的差递增的情况，则说明距离最优分割越来越远，则停止继续尝试
if(diff < Math.abs(left - right)) {
break;
}
diff = Math.abs(left - right);
min = Math.min(min, Math.max(left, right));
}
return min;
}``````

``````    public int splitArray(int[] nums, int m)
{
int L = nums.length;
//记录0-i的元素和
int[] S = new int[L+1];
S[0]=0;
for(int i=0; i<L; i++)
S[i+1] = S[i]+nums[i];

//如果m=1，则最小分割结果对应的是整个数组中所有元素的和
int[] dp = new int[L];
for(int i=0; i<L; i++)
dp[i] = S[L]-S[i];

for(int s=1; s<m; s++)
{
for(int i=0; i<L-s; i++)
{
dp[i]=Integer.MAX_VALUE;
for(int j=i+1; j<=L-s; j++)
{
int t = Math.max(dp[j], S[j]-S[i]);
if(t<=dp[i])
dp[i]=t;
else
break;
}
}
}

return dp[0];
}``````

## 思路二：二分法

``````    public int splitArray2(int[] nums, int m) {
long sum = 0;
int max = Integer.MIN_VALUE;
for(int i = 0 ; i<nums.length ; i++) {
max = Math.max(max, nums[i]);
sum += nums[i];
}
if(m == 1) {
return (int)sum;
}
long lft = max;
long rgt = sum;
while(lft <= rgt) {
long mid = (lft + rgt) / 2;
if(valid(nums, m, mid)) {
rgt = mid - 1;
}else {
lft = mid + 1;
}
}
return (int) lft;

}

public boolean valid(int[] nums, int m, long target) {
int count = 1;
long sum = 0;
for(int i = 0 ; i<nums.length ; i++) {
sum += nums[i];
if(sum > target) {
sum = nums[i];
count++;
if(count > m) {
return false;
}
}
}
return true;
}``````