import java.util.*;
/**
* NC347 分割数组
* @author d3y1
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param num int整型ArrayList
* @param m int整型
* @return int整型
*/
public int splitMin (ArrayList<Integer> num, int m) {
return solution1(num, m);
// return solution2(num, m);
}
/**
* 动态规划
*
* dp[i][j]表示数组num前i个数分成j个非空连续子数组的最小的最大和(非空连续子数组)
*
* dp[i][j] = Math.min(dp[i][j], Math.max(dp[k][j-1], sum)) , 1<=i<=n && 1<=j<=min(i,m) && j-1<=k<=i-1
*
* @param num
* @param m
* @return
*/
private int solution1(ArrayList<Integer> num, int m){
int n = num.size();
int[][] dp = new int[n+1][m+1];
// 前i个数
for(int i=1; i<=n; i++){
// 分成j个非空连续子数组
for(int j=1; j<=i&&j<=m; j++){
dp[i][j] = Integer.MAX_VALUE;
int sum = 0;
// 前k个数分成j-1个非空连续子数组
for(int k=i-1; k>=j-1; k--){
// sum = num[k+1,i] -> 第k+1到第i个数的和
sum += num.get(k);
// dp[k][j-1]: 数组num前k个数分成0个非空连续子数组 -> 无法实现
if(k>0 && j-1==0){
continue;
}
dp[i][j] = Math.min(dp[i][j], Math.max(dp[k][j-1], sum));
}
}
}
return dp[n][m];
}
/**
* 二分 + 贪心
* @param num
* @param m
* @return
*/
private int solution2(ArrayList<Integer> num, int m){
int n = num.size();
int max=0, sum=0;
int val;
for(int i=0; i<n; i++){
val = num.get(i);
max = Math.max(max, val);
sum += val;
}
int left = max;
int right = sum;
int mid;
// 二分
while(left <= right){
mid = (left+right)/2;
int cnt=1;
int part = 0;
for(int curr: num){
// 贪心
if(part+curr > mid){
cnt++;
part = curr;
}else{
part += curr;
}
}
if(cnt > m){
left = mid+1;
}else{
right = mid-1;
}
}
return left;
}
}