GuilinDev

Lc0410

05 August 2008

410. Split Array Largest Sum

给定一个由非负整数和一个整数 m 组成的数组 nums,您可以将数组拆分为 m 个非空连续子数组。

编写一个算法来最小化这 m 个子数组中的最大和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

Binary Search

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
    private static boolean feasible(int[] nums, int mid, int m) {
        int mDone = 1;
        int idx = 0;
        int sumSoFar = 0;
        while (idx < nums.length) {
            sumSoFar += nums[idx];
            if (sumSoFar > mid) {
                mDone++;
                sumSoFar = nums[idx];
                if (mDone > m) {
                    return false;
                }
            }
            idx++;
        }
        return true;
    }

    public int splitArray(int[] nums, int m) {
        int left = Arrays.stream(nums).max().getAsInt(), right = Arrays.stream(nums).sum();
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (feasible(nums, mid, m)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }
}

DP

dp[s,j] is the solution for splitting subarray n[j]…n[L-1] into s parts.

dp[s+1,i] = min{ max(dp[s,j], n[i]+…+n[j-1]) }, i+1 <= j <= L-s

ptifalls:

1, init when s== 1; start loop when s = 2;

2, for each s, loop i until n - 1 - (s - 1) to make sure the rest will form s - 1 parts;

3, same on j, until n - 1 - (s - 2) to make sure the rest will form s - 2 parts;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
    public int splitArray(int[] nums, int m) {
        int len = nums.length;
        int[] sum = new int[len + 1];
        sum[0] = 0;
        for (int i = 0; i < len; i++) {
            sum[i + 1] = sum[i] + nums[i];
        }

        int[][] dp = new int[m + 1][len];
        for (int i = 0; i < len; i++) {
            dp[1][i] = sum[len] - sum[i];
        }

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