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份,求这m份中最大和的最小值(即求极大的极小问题)。
因为我们知道切割的方法,用二分+搜索求解就可以了。
所谓二分,就是确定结果的最大值maxerf和最小值miner,取两者的中间值mid。而搜索便是:判断mid是否符合条件,如果符合,则令miner=mid+1,同时记录下ans,否则,令maxer=mid-1,以此类推,当miner>maxer时结束。
方法不难,但是我们还要注意一些细节上的问题:
(1)nums = [1,2147483647] ,m = 1 时,计算maxer的时候会越界,而且计算繁杂,应单独处理
(2)nums = [1,2147483647] ,m = 2 时,计算maxer的时候会越界,得到的maxer为负数,这时候,要令maxer = 2147483647。
(3)在搜索的时候,当当前和temp==mid时,要判断此时是否为数组的结尾,再确定sum是否加1。
class Solution {
public:
int splitArray(vector<int>& nums, int m) {
int n = nums.size() ;
if ( n == 0 )
return 0 ;
int miner = 0 , maxer = 0 ;
for ( int i = 0 ; i < n ; i ++ )
{
maxer += nums[i] ;
miner = max ( miner , nums[i] ) ;
}
if ( m == 1 )
return maxer ;
int ans = maxer ;
if ( maxer < 0 )
maxer = 2147483647 ;
miner = max ( miner , maxer / m ) ;
while ( miner <= maxer )
{
int mid = ( (unsigned int) miner + maxer ) / 2 , temp = 0 , sum = 1 ;
for ( int i = 0 ; i < n ; i ++ )
{
temp += nums[i] ;
if ( temp > mid )
{
sum ++ ;
temp = nums[i] ;
}
else if ( temp == mid )
{
if ( i != n - 1 )
sum ++ ;
temp = 0 ;
}
}
if ( sum <= m )
{
ans = mid ;
maxer = mid - 1 ;
}
else
miner = mid + 1 ;
}
return ans ;
}
};