
这一题的大意是说给出一个正整数数组,和一个整数k,现在让我们划分出k个区间,使得这些子数组区间中的最大值最小。换句话说,就是分成的k个区间中,肯定有一个子数组的和是最大值,希望让这个最大值最小。
看到最大值最小这种字眼,很明显的二分答案,即我们用二分的方式猜这个最大值,
假设这个最大值为x,
那么我们在check数组中验证最大值为x时,是否能够形成小于等于k个子数组,如果能,那么就符合,我们继续二分,希望这个x更小,使得符合最小化最大值的条件。
这里的判断方法经常用到:
cpp
力扣1760. 袋子里最少数目的球
力扣2064. 分配给商店的最多商品的最小值
都类似
完整代码如下:
cpp
class Solution {
public:
bool check(long long x,vector<int>& nums,int k)
{
//将这这个数组分为k分
// 使它们中的最大值最小
int sum=0;
int cnt=1;
for(int i=0;i<nums.size();i++)
{
if(sum+nums[i]>x)
{
sum=nums[i];
cnt++;
if(cnt>k)
{
return false;
}
continue;
}
else
{
sum+=nums[i];
}
}
return true;
}
int splitArray(vector<int>& nums, int k) {
//nums
// 最小化最大值
int n=nums.size();
int sum=0;
for(int i=0;i<nums.size();i++)
{
sum+=nums[i];
}
int l=*max_element(nums.begin(), nums.end());;
long long r=sum;
long long ans=INT_MAX;
while(l<=r)
{
long long mid=(l+r)/2;
if(check(mid,nums,k))
{
ans=min(ans,mid);
r=mid-1;
}
else
{
l=mid+1;
}
}
return ans;
}
};
我们要注意的是这里的l必须是数组中的最大值,如果过小会出错,为什么l要是数组中的最大值
因为我们二分的对象就是数组中的最大值,如果是不符合最大值但仍然在数组中,那么它有可能也符合check函数的条件,但很明显不符合最大值的要求,而子数组的最大值左边界就是一种极端情况,
任何合法的最大分段和(我们要二分的目标值)一定要 ≥ 数组中最大的单个元素。因为如果连数组中的单个最大值都放不下,那么很明显无非划分成子数组。
这里用来找一个数组中的最大值用的是
cpp
*max_element(nums.begin(), nums.end());
需要会用,比较方便。
时间复杂度为O(nlogn)