持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情
每日刷题 2022.06.07
- leetcode原题链接:leetcode.cn/problems/ko…
- 难度:中等
- 方法:二分搜索
题目
- 珂珂喜欢吃香蕉。这里有 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
解题思路
暴力做法
- 分析:
- 珂珂需要在警察回来之前(
h小时内)吃掉所有的香蕉 - 并且
h小时内,需要以最慢的速度k将全部香蕉🍌吃完 - 还需要注意⚠️:如果当前的堆中的香蕉小于
k根,那么吃完堆中的香蕉后,这个小时内就不会再吃了。(也就是多了会剩出来,少了不能添,每一堆香蕉并不能合并处理,只能一堆堆的)
- 珂珂需要在警察回来之前(
- 遍历
piles数组,依次去尝试珂珂在h小时内吃掉所有的香蕉的最小速度k,k的范围:1 ~ max(数组中的最大值) - 理解清楚了题意之后,就比较简单了。那么就每次判断当前这堆香蕉🍌对于吃香蕉的速度
k,最多能够几个小时处理完。将所有的小时加起来就是吃完所有的香蕉需要的时间。
二分查找+排序(学习大佬的解题思路)
- 经典的二分查找题目
- 因为根据题意可知:每堆香蕉之间都是相互独立的,且每堆香蕉最小的吃完时间
1(当其小于等于K的时候),由此可推出pile[i] / k就是每个香蕉堆需要的时间,注意:这里需要向上取整,因为不足的还需要1小时来完成。 - 判断是否能够二分:需要有二段性,本题可以二分
k,因为k是递增的,且- 小于
K的值,总时间total > h - 大于
K的值,总时间一定total <= h
- 小于
- 那么剩下就需要确定二分的范围:
- 当堆里的香蕉小于
k的时候,需要使用1小时 - 当堆里的香蕉大于
k,且为数组中最大的元素值,那么k取比其大的元素值都是没有用的,因为k = max(piles[i])等价,因为我们要找最小的K
- 当堆里的香蕉小于
- 因此,二分的范围就是
1 ~ 数组中最大的元素值 - 其中的比较
check函数,只需要每次计算当前的K是否小于等于h即可,因为我们要找的是等于h时的最小的k,因此右边是<=,左边是>,那么只需要返回右边,就可以找到第一个最小的等于h的。
AC代码
/**
* @param {number[]} piles
* @param {number} h
* @return {number}
*/
var minEatingSpeed = function(piles, h) {
// 在 h 小时内吃掉所有香蕉的最小速度 k(k为整数)
// k表示在在每一个小时内能够吃掉的香蕉数
// 先考虑恰巧能够在规定时间内吃完所有香蕉的,k
//从小到大进行排序
piles.sort((a, b) => {
return a - b;
})
const n = piles.length;
function check(mid) {
let re = 0;
// 传递过来的就是:具体的值
// 计算所需要的小时数
let tt = 0;
for(let i = 0; i < n; i++) {
// 对于每一堆香蕉,珂珂吃完的最长时间
tt += Math.ceil(piles[i] / mid);
}
// return n + Math.ceil(re / mid);
return tt;
}
// 二分查找
let l = 0, r = piles[n - 1] + 1;
while(l + 1 != r) {
let mid = l + parseInt((r - l) / 2);
let t = check(mid);
// 升序排序得到的
if(t <= h) {
r = mid;
}else {
l = mid;
}
}
// 最终的r就是等于h且最小的k
return r;
};