目录
例题一
珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 h 小时后回来。
珂珂可以决定她吃香蕉的速度 k (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 k 根。如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。
珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。
返回她可以在 h 小时内吃掉所有香蕉的最小速度 k(k 为整数)。
示例 1:
输入:piles = [3,6,7,11], h = 8
输出:4
示例 2:输入:piles = [30,11,23,4,20], h = 5
输出:30
示例 3:输入:piles = [30,11,23,4,20], h = 6
输出:23
提示:
1 <= piles.length <= 104
piles.length <= h <= 109
1 <= piles[i] <= 109
解题思路:
我们知道,二分要有边界和单调性,在二分答案中,边界很容易看出来,这题是1和piles里最大的数。而单调性,这题就是对于一个速度,当这个速度小于某个值(就是要求的临界速度)时,不符合要求,当成是0,大于这个临界速度,当成是1,于是化成在数组0,0,0。。。1,1,1中寻找下标最小的1。
class Solution {
public:
bool check(vector<int>& piles,int h,int ans)
{
int sum=0;
for(int i=0;i<piles.size();i++)
{
sum+=(piles[i]-1)/ans+1;//遍历每个piles[i],计算出该ans下的时间
}
if(sum<=h)return true;//如果时间足够小,就是可以满足
else return false;
}
int minEatingSpeed(vector<int>& piles, int h) {
int l=1,r=1000000000; //初始化边界
while(l<r)
{
int mid=l+(r-l)/2; //这里防止溢出,然后是向左寻找答案的模板
if(check(piles,h,mid))r=mid;
else l=mid+1;
}
return l;
}
};
例题二
在代号为 C-137 的地球上,Rick 发现如果他将两个球放在他新发明的篮子里,它们之间会形成特殊形式的磁力。Rick 有 n 个空的篮子,第 i 个篮子的位置在 position[i] ,Morty 想把 m 个球放到这些篮子里,使得任意两球间 最小磁力 最大。
已知两个球如果分别位于 x 和 y ,那么它们之间的磁力为 |x - y| 。
给你一个整数数组 position 和一个整数 m ,请你返回最大化的最小磁力。
示例 1:
输入:position = [1,2,3,4,7], m = 3
输出:3
解释:将 3 个球分别放入位于 1,4 和 7 的三个篮子,两球间的磁力分别为 [3, 3, 6]。最小磁力为 3 。我们没办法让最小磁力大于 3 。
示例 2:输入:position = [5,4,3,2,1,1000000000], m = 2
输出:999999999
解释:我们使用位于 1 和 1000000000 的篮子时最小磁力最大。
提示:
n == position.length
2 <= n <= 10^5
1 <= position[i] <= 10^9
所有 position 中的整数 互不相同 。
2 <= m <= position.length
解题思路:
其实看这问题“返回最大化的最小磁力”,就知道这是二分答案的题目。首先,只需要考虑相邻之间的磁力,因为不相邻的球的磁力肯定比相邻的大,我们要的是最小磁力。
其次,我们要贪心地尽可能将球放得相隔远一点,那最左边的篮子你放不放球?思考一下,放最左边百利而无一害,所以必须放。
还需要注意的是,对于要check的一个磁力,是不是每个球的间隔必须是这么大?不必要。我们每次放都是放满足大于等于这个磁力的最小磁力。
那有人就要说了,如果每个磁力都大于这个check的磁力怎么办?不要紧,关键看能不能放得下m个球,如果放得下,说明check的磁力够小,否则太大。依次来二分答案即可
class Solution {
public:
bool check(vector<int>& position,int m,int k)
{
int pre=position[0],sum=1; //第一个篮子必放
for(int i=1;i<position.size();i++)
{
if(position[i]-pre>=k) //找到能放的球最左边的篮子
{
sum++;pre=position[i];
}
}
if(sum<m)return false;
return true;
}
int maxDistance(vector<int>& position, int m) {
sort(position.begin(),position.end()); //将篮子从左到右排
int l=1,r=position.back()-position[0]; //边界
while(l<r)
{
int mid=l+(r-l+1)/2; //注意是最大化答案,所以是向右找的模板
if(check(position,m,mid))l=mid;
else r=mid-1;
}
return l;
}
};
例题三
给你一个整数数组 nums ,其中 nums[i] 表示第 i 个袋子里球的数目。同时给你一个整数 maxOperations 。
你可以进行如下操作至多 maxOperations 次:
选择任意一个袋子,并将袋子里的球分到 2 个新的袋子中,每个袋子里都有 正整数 个球。
比方说,一个袋子里有 5 个球,你可以把它们分到两个新袋子里,分别有 1 个和 4 个球,或者分别有 2 个和 3 个球。
你的开销是单个袋子里球数目的 最大值 ,你想要 最小化 开销。请你返回进行上述操作后的最小开销。
示例 1:
输入:nums = [9], maxOperations = 2
输出:3
解释:
- 将装有 9 个球的袋子分成装有 6 个和 3 个球的袋子。[9] -> [6,3] 。
- 将装有 6 个球的袋子分成装有 3 个和 3 个球的袋子。[6,3] -> [3,3,3] 。
装有最多球的袋子里装有 3 个球,所以开销为 3 并返回 3 。
示例 2:输入:nums = [2,4,8,2], maxOperations = 4
输出:2
解释:
- 将装有 8 个球的袋子分成装有 4 个和 4 个球的袋子。[2,4,8,2] -> [2,4,4,4,2] 。
- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,4,4,4,2] -> [2,2,2,4,4,2] 。
- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,4,4,2] -> [2,2,2,2,2,4,2] 。
- 将装有 4 个球的袋子分成装有 2 个和 2 个球的袋子。[2,2,2,2,2,4,2] -> [2,2,2,2,2,2,2,2] 。
装有最多球的袋子里装有 2 个球,所以开销为 2 并返回 2 。
示例 3:输入:nums = [7,17], maxOperations = 2
输出:7
提示:
1 <= nums.length <= 105
1 <= maxOperations, nums[i] <= 109
解题思路:
这题也是个模板题,二分出一个答案,检验时遍历nums,找一下规律可知,要将nums[i]分成最多球也小于等于ans,需要(nums[i]-1)/ans下操作,套公式即可。
还有一些经典例题,供读者练习:
如果觉得博文有用,不妨点点关注,你的支持是我最大的动力!