leetcode 410. 分割数组的最大值(二分法)
1. 题目描述
给定一个非负整数数组和一个整数 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 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2. 思路
核心,二分查找各个子数组和的最大值的最小情况 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。
3. 代码
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; } }