410. Split Array Largest Sum

来源:互联网 发布:雨田开版软件 编辑:程序博客网 时间:2024/05/21 09:42

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)

Input:nums = [7,2,5,10,8]m = 2Output:18Explanation: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.

动态规划的思路http://www.cnblogs.com/grandyang/p/5933787.html
递推公式val = max(dp[i - 1][k], sums[j] - sums[k]);
dp[i][j] = min(dp[i][j], val);
其中dp[i][j]:j个数字分成i组。初始化为INT_MAX
sums:保存前j个数字的和。
假如j = 3, i = 3, dp[2][0],dp[2][1]为INT_MAX,因为0个或者1个数字分成2组是不可能的,所以从k=2开始,val = max(dp[2][2], sums[3] - sum[2])
也就是前面两个数字分的两组中的最小值和第三个数字比较,得到最大值。
继续j = 4, i = 3, 同理从k = 2开始, val = max(dp[2][2], sums[4] - sums[2]), 也就是前面两个数字分成两组,后面两个数字为一组比较
k = 3, val = max(dp[2][3], sums[4] - sums[3])
前面3个数字分成两组得到的最大值, 后面一个数字比较.

class Solution {public:    int splitArray(vector<int>& nums, int m) {        int n = nums.size();        vector<int> sums(n + 1, 0);        vector<vector<int>> dp(m + 1, vector<int>(n + 1, INT_MAX));        dp[0][0] = 0;        for (int i = 1; i <= n; ++i) {            sums[i] = sums[i - 1] + nums[i - 1];        }        for (int i = 1; i <= m; ++i) {            for (int j = 1; j <= n; ++j) {                for (int k = i - 1; k < j; ++k) {                    int val = max(dp[i - 1][k], sums[j] - sums[k]);                    dp[i][j] = min(dp[i][j], val);                }            }        }        return dp[m][n];    }};

二分思路
可以用(1,2,3,4,5), m= 3走一遍
https://discuss.leetcode.com/topic/61324/clear-explanation-8ms-binary-search-java/9

1.The answer is between maximum value of input array numbers and sum of those numbers.2.Use binary search to approach the correct answer. We have l = max number of array; r = sum of all numbers in the array;Every time we do mid = (l + r) / 2;3.Use greedy to narrow down left and right boundaries in binary search.3.1 Cut the array from left.3.2 Try our best to make sure that the sum of numbers between each two cuts (inclusive) is large enough but still less thanmid.3.3 We'll end up with two results: either we can divide the array into more than m subarrays or we cannot.If we can, it means that the mid value we pick is too small because we've already tried our best to make sure each part holds as many non-negative numbers as we can but we still have numbers left. So, it is impossible to cut the array into m parts and make sure each parts is no larger than mid. We should increase m. This leads to l = mid + 1;If we can't, it is either we successfully divide the array into m parts and the sum of each part is less than mid, or we used up all numbers before we reach m. Both of them mean that we should lower mid because we need to find the minimum one. This leads to r = mid - 1;
public class Solution {    public int splitArray(int[] nums, int m) {        int max = 0; long sum = 0;        for (int num : nums) {            max = Math.max(num, max);            sum += num;        }        if (m == 1) return (int)sum;        //binary search        long l = max; long r = sum;        while (l <= r) {            long mid = (l + r)/ 2;            if (valid(mid, nums, m)) {                r = mid - 1;            } else {                l = mid + 1;            }        }        return (int)l;    }    public boolean valid(long target, int[] nums, int m) {        int count = 1;        long total = 0;        for(int num : nums) {            total += num;            if (total > target) {                total = num;                count++;                if (count > m) {                    return false;                }            }        }        return true;    }}
原创粉丝点击