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.

 

Approach #1:  Plan Recursion (Up to Bottom)

class Solution {
public:
    int splitArray(vector<int>& nums, int m) {
        const int n = nums.size();
        sums_ = vector<int>(n);
        mem_ = vector<vector<int>>(n, vector<int>(m + 1, INT_MAX));
        sums_[0] = nums[0];
        for (int i = 1; i < n; ++i) {
            sums_[i] = nums[i] + sums_[i-1];        // prefix sum
        }
        return helper(nums, n-1, m);
    }
private:
    int helper(const vector<int>& nums, int k, int m) {
        if (m == 1) return sums_[k];        // split one group. 
        if (m > k + 1) return INT_MAX;      // split groups more than the elements.
        if (mem_[k][m] != INT_MAX) return mem_[k][m];       // return the have memeried status
        int ans = INT_MAX;
        for (int i = 0; i < k; ++i) 
            ans = min(ans, max(helper(nums, i, m-1), sums_[k] - sums_[i]));     // calculation minimize largest sum. 
        return mem_[k][m] = ans;
    }
    vector<vector<int>> mem_;
    vector<int> sums_;
};

Runtime: 116 ms, faster than 2.38% of C++ online submissions for Split Array Largest Sum.

 

Approach #2: DP (Bottom to Up)

class Solution {
public:
    int splitArray(vector<int>& nums, int m) {
        const int n = nums.size();  // if I don't use const it will not compile successfully.
        vector<int> sum(n+1);
        vector<vector<int>> dp(m+1, vector<int>(n, INT_MAX));
        sum[0] = nums[0];
        for (int i = 1; i < n; ++i) 
            sum[i] = sum[i-1] + nums[i];
        for (int i = 0; i < n; ++i) 
            dp[1][i] = sum[i];      // the status with only one group;
        for (int i = 2; i <= m; ++i) {
            for (int j = i-1; j < n; ++j) {
                for (int k = 0; k < j; ++k) {
                    dp[i][j] = min(dp[i][j], max(dp[i-1][k], sum[j] - sum[k]));
                }
            }
        }
        return dp[m][n-1];
    }
};
Runtime: 116 ms, faster than 2.38% of C++ online submissions for Split Array Largest Sum.

 

Approach #3: Binary Search:

class Solution {
public:
    int splitArray(vector<int>& nums, int m) {
        int l = 0, r = 0;
        for (auto& num : nums) {    // if don't use auto& it won't compile successfully.
            l = max(l, num);
            r += num;        // the answer must exsit bewteen in the l and r.
        }
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if (canSplit(nums, m, mid))
                r = mid - 1;
            else 
                l = mid + 1;
        }
        return l;
    }
private:
    bool canSplit(vector<int>& nums, int m, int mid) {
        int c = 1;
        int sum = 0;
        for (auto& num : nums) {
            sum += num;
            if (sum > mid) {
                c++;
                sum = num;
            }
        }
        return c <= m;
    }
};

Runtime: 4 ms, faster than 49.91% of C++ online submissions for Split Array Largest Sum.

 

posted @ 2018-11-06 20:28  Veritas_des_Liberty  阅读(177)  评论(0编辑  收藏  举报