给定一个非负整数数组和一个整数 m,你须要将这个数组分红 m 个非空的连续子数组。设计一个算法使得这 m 个子数组各自和的最大值最小。 注意: 数组长度 n 知足如下条件: 1 ≤ n ≤ 1000 1 ≤ m ≤ min(50, n) 示例: 输入: nums = [7,2,5,10,8] m = 2 输出: 18 解释: 一共有四种方法将nums分割为2个子数组。 其中最好的方式是将其分为[7,2,5] 和 [10,8], 由于此时这两个子数组各自的和的最大值为18,在全部状况中最小。 来源:力扣(LeetCode) 连接:https://leetcode-cn.com/problems/split-array-largest-sum 著做权归领扣网络全部。商业转载请联系官方受权,非商业转载请注明出处。
核心,二分查找各个子数组和的最大值的最小状况 1. 子数组的最大值是有范围的,即在区间[max(nums),sum(nums)]之中。 2. 令l=max(nums),h=sum(nums),mid=(l+h)/2,计算数组和最大值不大于mid对应的子数组个数cnt(这个是关键!) 3. 若是cnt>m,说明划分的子数组多了,即咱们找到的mid偏小,故l=mid+1; 4. 若是cnt<=m,说明划分的子数组少了,即mid偏大(或者正好就是目标值),故h=mid。
class Solution { public int splitArray(int[] nums, int m) { /**子数组的最大值是有范围的,即在区间[max(nums),sum(nums)]之中。*/ long l = nums[0]; long h = 0; for (int i : nums) { h += i;//max(nums) l = l > i ? l : i;//sum(nums) } /**计算数组和最大值不大于mid对应的子数组个数cnt*/ while (l<h) {//二分法找分割数组的最大值 long mid = (l + h) / 2; long temp = 0; int cnt = 1;//初始值为1, for(int i:nums) { temp += i; if(temp>mid) {//若是超过mid,开启新的一组 temp = i;//每一个子数组和 ++cnt;//子数组个数 } } if(cnt>m) l = mid + 1;//若是cnt>m,说明划分的子数组多了,即咱们找到的mid偏小,故l=mid+1; else h = mid;//若是cnt<=m,说明划分的子数组少了,即mid偏大(或者正好就是目标值),故h=mid。 } return (int)l; } }