非負の整数で構成される配列と整数が与えられ メートル、あなたはに、配列を分割することができます メートル 非空で連続サブアレイ。これらの中で最大の総和最小化するアルゴリズムを書く m個の サブアレイを。
注:
場合 、nは 、配列の長さであり、以下の制約が満たされていると仮定する。
- 1≤ N ≤1000年
- 1≤ M ≤分(50、 N)
例:
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.
思考:バイナリ答え:セグメント小さなスペースは、近いnに、最低の合計が最大である場合(A [i])と、一つだけ間隔がある場合、その和[0〜N-1]。
次いで下限及び平均値が数値K、セクションに分割することができないセクションの数の数Kよりも大きい場合には上限バイナリは、解空間を探索の間になる、それはK mよりも大きいができる更なる増加、Mよりも小さいを表します代表者は、Kも小さい点であるべきです。
その最後の判断時に最初の判定開始注意して、終了を決定し、あれば上に、バーストを合計することがあります。
時間:ログ(合計(あい))* n個のスペース:(N)
class Solution {
public int splitArray(int[] nums, int m) {
if(nums == null || nums.length == 0) {
return 0;
}
long start = 0, end = 0;
for(int i = 0; i < nums.length; i++) {
start = Math.max(start, nums[i]);
end += nums[i];
}
while(start + 1 < end) {
long mid = start + (end - start) / 2;
if(cansplit(nums, mid) > m) {
start = mid;
} else {
// cansplit(nums, mid) < m;
end = mid;
}
}
// first check start; then check end;
if(cansplit(nums, start) > m) {
return (int)end;
}
return (int)start;
}
private int cansplit(int[] nums, long sumlimit) {
int count = 0;
int i = 0;
long sum = 0;
while(i < nums.length) {
while(i < nums.length && sum + nums[i] <= sumlimit) {
sum += nums[i];
i++;
}
count++;
sum = 0;
}
return count;
}
}
アイデア2:この問題は、DFS +メモキャッシュをDPことができます
1つのセグメント - Leftsum prefixsum段落は、決定されるカット部分問題Mが続いてもよい先行
時間:O(M * N ^ 2)容量:O(M * N);すべてが正の場合Dpは、負のケースを有するように拡張することができ、二分探索又は優勢上記;
class Solution {
public int splitArray(int[] nums, int m) {
if(nums == null || nums.length == 0) {
return 0;
}
int n = nums.length;
int[] prefixsum = new int[n+1];
prefixsum[0] = 0;
for(int i = 1; i <= n; i++) {
prefixsum[i] = prefixsum[i - 1] + nums[i - 1];
}
int[][] cache = new int[n][m+1];
return splitArrayHelper(0, m, cache, nums, prefixsum);
}
private int splitArrayHelper(int j, int m, int[][] cache, int[] nums,
int[] prefixsum) {
int n = nums.length;
if(m == 1) {
return prefixsum[n] - prefixsum[j];
}
if(cache[j][m] != 0) {
return cache[j][m];
}
int res = Integer.MAX_VALUE;
for(int k = j; k < n - 1; k++) {
// j ~k sum;
int leftsum = prefixsum[k+1] - prefixsum[j];
// k+1 ~ n sum;
int rightsum = splitArrayHelper(k+1, m - 1, cache, nums, prefixsum);
res = Math.min(res, Math.max(leftsum, rightsum));
}
cache[j][m] = res;
return res;
}
}