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:
Given m satisfies the following constraint: 1 ≤ m ≤ length(nums) ≤ 14,000.
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.
分析:暴力解法
虽然要把数组分成几份,但是因为数组里的元素是连续的,所以,我们可以把前面部分当成第一份,然后找出后边部分分出 m - 1次时最大的和。所以递归方法可解。但是,很明显,cost太高了。
1 public class Solution { 2 //brute-force approach 3 public int splitArray(int[] nums, int m) { 4 long[] sums = new long[nums.length]; 5 sums[0] = nums[0]; 6 7 for (int i = 1; i < sums.length; i++) { 8 sums[i] = sums[i - 1] + nums[i]; 9 } 10 11 return (int) helper(nums, sums, 0, sums.length - 1, m); 12 } 13 14 public long helper(int[] nums, long[] sums, int start, int end, int k) { 15 if (k <= 0) 16 return Integer.MAX_VALUE; 17 if (k == 1) { 18 if (start == 0) { 19 return sums[end]; 20 } else { 21 return sums[end] - sums[start - 1]; 22 } 23 } 24 long min = Long.MAX_VALUE; 25 26 for (int i = start; i <= end; i++) { 27 28 long leftSum; 29 if (start == 0) { 30 leftSum = sums[i]; 31 } else { 32 leftSum = sums[i] - sums[start - 1]; 33 } 34 35 min = Math.min(min, Math.max(leftSum, helper(nums, sums, i + 1, end, k - 1))); 36 } 37 return min; 38 } 39 }
第二种方法:
首先找出数组的最大值max和所有值的和sum。然后那个最小值一定是在max和sum之间。 所以可以利用binary search来寻找。
reference: https://discuss.leetcode.com/topic/61315/java-easy-binary-search-solution-8ms
1 public class Solution { 2 public int splitArray(int[] nums, int m) { 3 long sum = 0; 4 int max = 0; 5 for (int num : nums) { 6 max = Math.max(max, num); 7 sum += num; 8 } 9 return (int) binary(nums, m, sum, max); 10 } 11 12 private long binary(int[] nums, int m, long high, long low) { 13 long mid = 0; 14 while (low <= high) { 15 mid = (high + low) / 2; 16 if (valid(nums, m, mid)) { 17 high = mid - 1; 18 } else { 19 low = mid + 1; 20 } 21 } 22 return low; 23 } 24 25 private boolean valid(int[] nums, int m, long max) { 26 int cur = 0, count = 1; 27 for (int num : nums) { 28 cur += num; 29 if (cur > max) { 30 cur = num; 31 count++; 32 if (count > m) { 33 return false; 34 } 35 } 36 } 37 return true; 38 } 39 }