給定一個非負整數數組和一個整數 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; } }