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

Binary Search + Greedy是效率比較高的方法,假設把nums array分成每個數字自己一組(m = nums.size()),這樣最大的subarray就是數列裡最大的數。如果所有數字看作一組(m = 1),那最大的subarray就是所有數字的總和。那麼這題要求的值必然介於上面兩個值之間。所以我們可以先界定出二分查找法的左右邊界。

每一個binary search iteration都會藉由當前的左右邊界找出一個中間值,會loop through所有數字一遍看看是否能找到subarrays的最大的和且小於等於當前mid值。

// Binary Search + Greedy
bool canSplit(int target, vector<int>& nums, int m) {
    int cnt = 1;
    long long curSum = 0;
    for (int i = 0; i < nums.size(); ++i) {
        curSum += nums[i];
        if (curSum > target) {
            curSum = nums[i];
            ++cnt;
            if (cnt > m) return false;
        }
    }
    return true;
}
int splitArray(vector<int>& nums, int m) { // time: O(nlogn); space: O(1)
    long long left = 0, right = 0;
    for (int num : nums) {
        left = max(left, (long long)num);
        right += num;
    }
    if (m == 1) return (int)right;
    while (left < right) {
        long long mid = left + (right - left) / 2;
        if (canSplit(mid, nums, m)) right = mid;
        else left = mid + 1;
    }
    return (int)left;
}

這題也可以用Dynamic programming來做,dp[i][j]代表前j個數字形成的i個子數列中最小的子陣列最大和。

假設k為中間任意數量的數字,dp[i - 1][k]代表前k個數字形成的i-1個子數列中最小的最大子數列和。

sums[j] - sums[k]就是最後一個子數列的和。要跟前i - 1個子數列比較紀錄最大值。最後再跟當前的dp[i][j]結果比較紀錄最小值。

Last updated

Was this helpful?