大家好今天给大家分享下一道 LeetCode 中等难度 的题目 爱吃香蕉的珂珂](leetcode-cn.com/problems/co…)
这里主要是分享思路和注释,供大家更好的理解题目解法,代码部分是参考LeetCode 转写成javascript 代码,
题目
珂珂喜欢吃香蕉。这里有 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.有N堆香蕉,每堆的数量为piles[i],如果一堆中香蕉数量如果少于k根,也需要消耗1个小时,所以每堆需要花去的时间为 Math.ceil(piles[i]/k)
2.由于警卫会在H小时候回来,所以花去的总时间 t<=H
3.需要求的值是最小速度k,所以t必须尽量大。
4.在不考虑H 的情况下,K最小为1,最大值为Math.max(piles)
解法有2种
1.暴力法
2.二分查找法
解法一:暴力法
思路
1.k属于[1,max(piles)]
2.迭代求出最小的K
*/
var minEatingSpeed = function (piles, h) {
let maxSpeed = Math.max(...piles);
// 求出k值的取值范围
for (let k = 1; k <= maxSpeed; k++) {
let t = 0;
// 求出需要花好多时间
for (let j = 0; j < piles.length; j++) {
t += Math.ceil(piles[j] / k);
}
// 当面满足条件的时候 返回k则为最小的k值
if (t <= h) {
return k;
}
}
};
/* 复杂度
时间 O(n^2)
空间 O(1)
*/
解法二:二分法
思路
1.由于k属于[1,max(piles)]
2.[1,max(piles)] 是升序数组,且是查找当中的一个值,让我们想到了二分法
3.但是这里的二分的循环条件不再是while(l<=r) 而是 while(pass(mid)),我们通过这个函数来判断k在左边还是右边
*/
var minEatingSpeed = function (piles, h) {
let l = 0;
let r = Math.max(...piles);
while (l <= r) {
const mid = Math.floor(l + (r - l) / 2);
// 由于是求k的最小值,所以如果通过,则说明k还可以更小于是收敛右边的区间
if (pass(mid)) {
r = mid - 1;
} else {
l = mid + 1;
}
}
return l;
// 求得通过的情况
function pass(mid) {
let t = 0;
for (let j = 0; j < piles.length; j++) {
t += Math.ceil(piles[j] / mid);
}
// 如果满足条件则返回true反之则为false
return t <= h;
}
};
/* 复杂度
时间 O(nlogn)
空间 O(1)
*/
总结
这道题 ,考察的还是大家对二分查找应用,需要大家理解清楚 k h piles 这3个元素之间的关系,就能分析如何使用二分查找法
大家可以看看我分享的一个专栏(前端搞算法)里面有更多关于算法的题目的分享,希望能够帮到大家,我会尽量保持每天晚上更新,如果喜欢的麻烦帮我点个赞,十分感谢
文章内容目的在于学习讨论与分享学习算法过程中的心得体会,文中部分素材来源网络,如有侵权,请联系删除,邮箱 182450609@qq.com