提交 fa05b232 编写于 作者: L luzhipeng

feat: 盛水问题,香蕉问题

上级 7e0dd7e1
......@@ -16,6 +16,11 @@ leetcode 题解,记录自己的 leecode 解题之路。
> 只有熟练掌握基础的数据结构与算法,才能对复杂问题迎刃有余
## 食用说明
- 经典题目的解析的目录部分,前面有🆕的代表是最新更新的
- 将来会在这里更新anki卡片
## 精彩预告
......@@ -79,6 +84,8 @@ leetcode 题解,记录自己的 leecode 解题之路。
- [900.rle-iterator](./problems/900.rle-iterator.md)
- [322.coin-change](./problems/322.coin-change.md)
- [518.coin-change-2](./problems/518.coin-change-2.md)
- 🆕 [11.container-with-most-water](./problems/11.container-with-most-water.md)
- 🆕 [875.koko-eating-bananas](./problems/875.koko-eating-bananas.md)
#### 困难难度
......
## 题目地址
https://leetcode.com/problems/container-with-most-water/description/
## 题目描述
```
Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water.
Note: You may not slant the container and n is at least 2.
```
![11.container-with-most-water-question](../assets/problems/11.container-with-most-water-question.jpg)
```
The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.
Example:
Input: [1,8,6,2,5,4,8,3,7]
Output: 49
```
## 思路
符合直觉的解法是,我们可以对两两进行求解,计算可以承载的水量。 然后不断更新最大值,最后返回最大值即可。
这种解法,需要两层循环,时间复杂度是O(n^2)
eg:
```js
// 这个解法比较暴力,效率比较低
// 时间复杂度是O(n^2)
let max = 0;
for(let i = 0; i < height.length; i++) {
for(let j = i + 1; j < height.length; j++) {
const currentArea = Math.abs(i - j) * Math.min(height[i], height[j]);
if (currentArea > max) {
max = currentArea;
}
}
}
return max;
```
> 这种符合直觉的解法有点像冒泡排序, 大家可以稍微类比一下
那么有没有更加优的解法呢?我们来换个角度来思考这个问题,上述的解法是通过两两组合,这无疑是完备的,
那我门是否可以先计算长度为n的面积,然后计算长度为n-1的面积,... 计算长度为1的面积。 这样去不断更新最大值呢?
很显然这种解法也是完备的,但是似乎时间复杂度还是O(n ^ 2), 不要着急。
考虑一下,如果我们计算n-1长度的面积的时候,是直接直接排除一半的结果的。
如图:
![11.container-with-most-water](../assets/problems/11.container-with-most-water.png)
比如我们计算n面积的时候,假如左侧的线段高度比右侧的高度低,那么我们通过左移右指针来将长度缩短为n-1的做法是没有意义的,
因为`新的形成的面积变成了(n-1) * heightOfLeft 这个面积一定比刚才的长度为n的面积nn * heightOfLeft 小`
也就是说最大面积`一定是当前的面积或者通过移动短的线段得到`
## 关键点解析
- 双指针优化时间复杂度
## 代码
```js
/*
* @lc app=leetcode id=11 lang=javascript
*
* [11] Container With Most Water
*
* https://leetcode.com/problems/container-with-most-water/description/
*
* algorithms
* Medium (42.86%)
* Total Accepted: 344.3K
* Total Submissions: 790.1K
* Testcase Example: '[1,8,6,2,5,4,8,3,7]'
*
* Given n non-negative integers a1, a2, ..., an , where each represents a
* point at coordinate (i, ai). n vertical lines are drawn such that the two
* endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together
* with x-axis forms a container, such that the container contains the most
* water.
*
* Note: You may not slant the container and n is at least 2.
*
*
*
*
*
* The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In
* this case, the max area of water (blue section) the container can contain is
* 49.
*
*
*
* Example:
*
*
* Input: [1,8,6,2,5,4,8,3,7]
* Output: 49
*
*/
/**
* @param {number[]} height
* @return {number}
*/
var maxArea = function(height) {
if (!height || height.length <= 1) return 0;
// 双指针来进行优化
// 时间复杂度是O(n)
let leftPos = 0;
let rightPos = height.length - 1;
let max = 0;
while(leftPos < rightPos) {
const currentArea = Math.abs(leftPos - rightPos) * Math.min(height[leftPos] , height[rightPos]);
if (currentArea > max) {
max = currentArea;
}
// 更新小的
if (height[leftPos] < height[rightPos]) {
leftPos++;
} else { // 如果相等就随便了
rightPos--;
}
}
return max;
};
```
## 题目地址
https://leetcode.com/problems/koko-eating-bananas/description/
## 题目描述
```
Koko loves to eat bananas. There are N piles of bananas, the i-th pile has piles[i] bananas. The guards have gone and will come back in H hours.
Koko can decide her bananas-per-hour eating speed of K. Each hour, she chooses some pile of bananas, and eats K bananas from that pile. If the pile has less than K bananas, she eats all of them instead, and won't eat any more bananas during this hour.
Koko likes to eat slowly, but still wants to finish eating all the bananas before the guards come back.
Return the minimum integer K such that she can eat all the bananas within H hours.
Example 1:
Input: piles = [3,6,7,11], H = 8
Output: 4
Example 2:
Input: piles = [30,11,23,4,20], H = 5
Output: 30
Example 3:
Input: piles = [30,11,23,4,20], H = 6
Output: 23
Note:
1 <= piles.length <= 10^4
piles.length <= H <= 10^9
1 <= piles[i] <= 10^9
```
## 思路
符合直觉的做法是,选择最大的堆的香蕉数,然后试一下能不能行,如果不行则直接返回上次计算的结果,
如果行,我们减少1个香蕉,试试行不行,依次类推。计算出刚好不行的即可。这种解法的时间复杂度是O(n)。
这道题如果能看出来是二分法解决,那么其实很简单。为什么它是二分问题呢?
我这里画了个图,我相信你看了就明白了。
![koko-eating-bananas](../assets/problems/koko-eating-bananas.png)
## 关键点解析
- 二分查找
## 代码
```js
/*
* @lc app=leetcode id=875 lang=javascript
*
* [875] Koko Eating Bananas
*
* https://leetcode.com/problems/koko-eating-bananas/description/
*
* algorithms
* Medium (44.51%)
* Total Accepted: 11.3K
* Total Submissions: 24.8K
* Testcase Example: '[3,6,7,11]\n8'
*
* Koko loves to eat bananas.  There are N piles of bananas, the i-th pile has
* piles[i] bananas.  The guards have gone and will come back in H hours.
*
* Koko can decide her bananas-per-hour eating speed of K.  Each hour, she
* chooses some pile of bananas, and eats K bananas from that pile.  If the
* pile has less than K bananas, she eats all of them instead, and won't eat
* any more bananas during this hour.
*
* Koko likes to eat slowly, but still wants to finish eating all the bananas
* before the guards come back.
*
* Return the minimum integer K such that she can eat all the bananas within H
* hours.
*
*
*
*
*
*
*
* Example 1:
*
*
* Input: piles = [3,6,7,11], H = 8
* Output: 4
*
*
*
* Example 2:
*
*
* Input: piles = [30,11,23,4,20], H = 5
* Output: 30
*
*
*
* Example 3:
*
*
* Input: piles = [30,11,23,4,20], H = 6
* Output: 23
*
*
*
*
* Note:
*
*
* 1 <= piles.length <= 10^4
* piles.length <= H <= 10^9
* 1 <= piles[i] <= 10^9
*
*
*
*
*
*/
function canEatAllBananas(piles, H, mid) {
let h = 0;
for(let pile of piles) {
h += Math.ceil(pile / mid);
}
return h <= H;
}
/**
* @param {number[]} piles
* @param {number} H
* @return {number}
*/
var minEatingSpeed = function(piles, H) {
let lo = 1,
hi = Math.max(...piles);
while(lo <= hi) {
let mid = lo + ((hi - lo) >> 1);
if (canEatAllBananas(piles, H, mid)) {
hi = mid - 1;
} else {
lo = mid + 1;
}
}
return lo; // 不能选择hi
};
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册