410. Split Array Largest Sum解题报告

Description:

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)

Example:

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.

Link:

https://leetcode.com/problems/split-array-largest-sum/

解题方法:

二分法:
假设给定一个值n, 来对整个数组进行划分,要求每个子数组的和都不超过n,那么能划分出多少个子数组肯定存在一个下限m_min(即最少能划分出几个子数组),而这道题其实就是求当给定一个m的时候,n最小是多少。
我们可以知道,当n越大,m_min就越小,当n等于整个数组的和的时候,m_min == 1。所以我们知道n的最大值为整个数组之和
当n越小,m_min就越大,因为每个子数组能包含的数就越少,就要做更多的划分。当n < 数组最大的数的时候,我们甚至都不能划分,所以综上所述,数组最大的数<=n<=数组之和

那么当给定一个n的时候,我们可以求出其能做出的最小划分m_min:用贪心就可以求出,时间复杂度为nums.size()

所以这道题就变成了,在一个递增区间查找n, 使得m_min <= m, 所以,我们可以用二分查找来解决这道题。

Time Complexity:

NlogN

完整代码:

int splitArray(vector& nums, int m) {
    long start = 0, end = 0;
    for(auto num: nums) {
        start = start > num ? start : num;
        end += num;
    }
    while(start + 1 < end) {
        long mid = start + (end - start) / 2;
        long checkR = check(nums, mid);
        if(checkR <= m)
            end = mid;
        else
            start = mid;
    }
    if(check(nums, start) <= m)
        return start;
    else
        return end;
}
int check(vector& nums, long m) {
    long sum = 0;
    int cnt = 1;
    for(int i = 0; i < nums.size(); i++) {
        sum += nums[i];
        if(sum > m) {
            sum = nums[i];
            cnt++;
        }
    }
    return cnt;
}

你可能感兴趣的:(410. Split Array Largest Sum解题报告)