珂珂喜欢吃香蕉。这里有 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 <= 10^4piles.length <= h <= 10^91 <= piles[i] <= 10^9
思路
这题正着想很困难的。但有一个很明显的点,速度最大为 piles 中最大的元素,记为 M. 这样,每次都能吃一堆,题目保证 piles.length <= h, 按这个速度吃,肯定是能吃完的。如果 h < piles.length, 无论啥速度都不行,因为题目说每次吃完一堆,这个小时内不再吃别的。
所以暴力的想法是枚举 1 到 M 的所有值,试试用该速度能不能吃完,然后返回最小速度。但我都想到这一步了,难道还不能加快一下搜索思路?
- 每次对半猜答案,如果当前答案满足要求,往小了找;
- 如果当前答案不满足要求,往大了找。
- 如此往复,最后剩三个答案,取最小可行的就完了。
以前从来没遇到过,二分法还能这么用。果然,刷题还是能锻炼思维的。
Code
class Solution {
public:
int minEatingSpeed(vector<int>& piles, int h) {
int end = -1;
for (int p : piles) {
end = max(end, p);
} // end must be feasible
int beg = 1, mid = 1;
while (beg <= end) {
mid = (beg + end) / 2;
if (feasible(piles, h, mid)) {
end = mid - 1;
} else {
beg = mid + 1;
}
}
return end + 1; // last feasible we do `end = mid - 1`, so here we revert this.
}
bool feasible(const vector<int>& piles, int h, int k) {
for (int p : piles) {
h -= ((p - 1) / k + 1);
if (h < 0) return false;
}
return true;
}
};