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.

思路:二分答案:如果细分空间越小,趋近于n, 最低的sum就是max(A[i]) ,如果只有一个区间,那么就是sum[0~n-1];

那么变成在lower bound和upper bound之间binary search解空间,如果平均值是一个数K,能把区间劈成多少个不大于K的区间个数,大于m则代表K还可以增加,小于m代表,K太大了,应该小点;

注意最后判断的时候,先判断start,然后判断end;还有sum有可能爆,改成long就可以了。

Time: log(sum(Ai))*n Space: O(N)

class Solution {
    public int splitArray(int[] nums, int m) {
        if(nums == null || nums.length == 0) {
            return 0;
        }
        long start = 0, end = 0;
        for(int i = 0; i < nums.length; i++) {
            start = Math.max(start, nums[i]);
            end += nums[i];
        }
        while(start + 1 < end) {
            long mid = start + (end - start) / 2;
            if(cansplit(nums, mid) > m) {
                start = mid;
            } else {
                // cansplit(nums, mid) < m;
                end = mid;
            }
        }
        // first check start; then check end;
        if(cansplit(nums, start) > m) {
            return (int)end;
        }
        return (int)start;
    }
    
    private int cansplit(int[] nums, long sumlimit) {
        int count = 0;
        int i = 0;
        long sum = 0;
        while(i < nums.length) {
            while(i < nums.length && sum + nums[i] <= sumlimit) {
                sum += nums[i];
                i++;
            }
            count++;
            sum = 0;
        }
        return count;
    }
}

思路2:这题可以用dp,DFS +memo cache

前面一段leftsum可以用prefixsum求出,后面是一个子问题 切成m - 1段;

Time: O(m*n^2) Space: O(m*n); Dp可以扩展成有负数的情况,如果全部是正数,还是上面的binary search占优势;

class Solution {
    public int splitArray(int[] nums, int m) {
        if(nums == null || nums.length == 0) {
            return 0;
        }
        int n = nums.length;
        int[] prefixsum = new int[n+1];
        prefixsum[0] = 0;
        for(int i = 1; i <= n; i++) {
            prefixsum[i] = prefixsum[i - 1] + nums[i - 1];
        }
        
        int[][] cache = new int[n][m+1];
        return splitArrayHelper(0, m, cache, nums, prefixsum);
    }
    
    private int splitArrayHelper(int j, int m, int[][] cache, int[] nums,
                                int[] prefixsum) {
        int n = nums.length;
        if(m == 1) {
            return prefixsum[n] - prefixsum[j];
        }
        if(cache[j][m] != 0) {
            return cache[j][m];
        }
        int res = Integer.MAX_VALUE;
        for(int k = j; k < n - 1; k++) {
            // j ~k sum;
            int leftsum = prefixsum[k+1] - prefixsum[j];
            // k+1 ~ n sum;
            int rightsum = splitArrayHelper(k+1, m - 1, cache, nums, prefixsum);
            res = Math.min(res, Math.max(leftsum, rightsum));
        }
        cache[j][m] = res;
        return res;
    }
}
发布了673 篇原创文章 · 获赞 13 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/u013325815/article/details/105191580