LeetCode每日一题--经营摩天轮的最大利润

leetCode算法系列--贪心算法

Posted by maybelence on 2021-04-14

前言

昨天说今天准备刷一下贪心算法,今天根据贪心算法的 tag 找了一个题目。题目本身没有特别难,整理完这题的解题思路之后,我会再找几题看看有没有共性思路可以整理分享一下。

题目描述

你正在经营一座摩天轮,该摩天轮共有4 个座舱 ,每个座舱 最多可以容纳 4 位游客 。你可以 逆时针 轮转座舱,但每次轮转都需要支付一定的运行成本 runningCost 。摩天轮每次轮转都恰好转动 1 / 4 周。

给你一个长度为 n 的数组 customerscustomers[i] 是在第 i 次轮转(下标从 0 开始)之前到达的新游客的数量。这也意味着你必须在新游客到来前轮转 i 次。每位游客在登上离地面最近的座舱前都会支付登舱成本 boardingCost ,一旦该座舱再次抵达地面,他们就会离开座舱结束游玩。

你可以随时停下摩天轮,即便是 在服务所有游客之前 。如果你决定停止运营摩天轮,为了保证所有游客安全着陆,将免费进行所有后续轮转 。注意,如果有超过 4 位游客在等摩天轮,那么只有 4 位游客可以登上摩天轮,其余的需要等待 下一次轮转

返回最大化利润所需执行的 最小轮转次数 。 如果不存在利润为正的方案,则返回 -1

wheeldiagram12.png

示例 1:

1
2
3
4
5
6
7
输入:customers = [8,3], boardingCost = 5, runningCost = 6
输出:3
解释:座舱上标注的数字是该座舱的当前游客数。
1. 8 位游客抵达,4 位登舱,4 位等待下一舱,摩天轮轮转。当前利润为 4 * $5 - 1 * $6 = $14 。
2. 3 位游客抵达,4 位在等待的游客登舱,其他 3 位等待,摩天轮轮转。当前利润为 8 * $5 - 2 * $6 = $28 。
3. 最后 3 位游客登舱,摩天轮轮转。当前利润为 11 * $5 - 3 * $6 = $37 。
轮转 3 次得到最大利润,最大利润为 $37 。

示例 2:
1
2
3
4
5
6
7
8
9
10
11
输入:customers = [10,9,6], boardingCost = 6, runningCost = 4
输出:7
解释:
1. 10 位游客抵达,4 位登舱,6 位等待下一舱,摩天轮轮转。当前利润为 4 * $6 - 1 * $4 = $20 。
2. 9 位游客抵达,4 位登舱,11 位等待(2 位是先前就在等待的,9 位新加入等待的),摩天轮轮转。当前利润为 8 * $6 - 2 * $4 = $40 。
3. 最后 6 位游客抵达,4 位登舱,13 位等待,摩天轮轮转。当前利润为 12 * $6 - 3 * $4 = $60 。
4. 4 位登舱,9 位等待,摩天轮轮转。当前利润为 * $6 - 4 * $4 = $80 。
5. 4 位登舱,5 位等待,摩天轮轮转。当前利润为 20 * $6 - 5 * $4 = $100 。
6. 4 位登舱,1 位等待,摩天轮轮转。当前利润为 24 * $6 - 6 * $4 = $120 。
7. 1 位登舱,摩天轮轮转。当前利润为 25 * $6 - 7 * $4 = $122 。
轮转 7 次得到最大利润,最大利润为$122 。

示例 3:

1
2
3
4
5
6
7
8
9
输入:customers = [3,4,0,5,1], boardingCost = 1, runningCost = 92
输出:-1
解释:
1. 3 位游客抵达,3 位登舱,0 位等待,摩天轮轮转。当前利润为 3 * $1 - 1 * $92 = -$89 。
2. 4 位游客抵达,4 位登舱,0 位等待,摩天轮轮转。当前利润为 is 7 * $1 - 2 * $92 = -$177 。
3. 0 位游客抵达,0 位登舱,0 位等待,摩天轮轮转。当前利润为 7 * $1 - 3 * $92 = -$269 。
4. 5 位游客抵达,4 位登舱,1 位等待,摩天轮轮转。当前利润为 12 * $1 - 4 * $92 = -$356 。
5. 1 位游客抵达,2 位登舱,0 位等待,摩天轮轮转。当前利润为 13 * $1 - 5 * $92 = -$447 。
利润永不为正,所以返回 -1 。

示例 4:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
输入:customers = [10,10,6,4,7], boardingCost = 3, runningCost = 8
输出:9
解释:
1. 10 位游客抵达,4 位登舱,6 位等待,摩天轮轮转。当前利润为 4 * $3 - 1 * $8 = $4 。
2. 10 位游客抵达,4 位登舱,12 位等待,摩天轮轮转。当前利润为 8 * $3 - 2 * $8 = $8 。
3. 6 位游客抵达,4 位登舱,14 位等待,摩天轮轮转。当前利润为 12 * $3 - 3 * $8 = $12 。
4. 4 位游客抵达,4 位登舱,14 位等待,摩天轮轮转。当前利润为 16 * $3 - 4 * $8 = $16 。
5. 7 位游客抵达,4 位登舱,17 位等待,摩天轮轮转。当前利润为 20 * $3 - 5 * $8 = $20 。
6. 4 位登舱,13 位等待,摩天轮轮转。当前利润为 24 * $3 - 6 * $8 = $24 。
7. 4 位登舱,9 位等待,摩天轮轮转。当前利润为 28 * $3 - 7 * $8 = $28 。
8. 4 位登舱,5 位等待,摩天轮轮转。当前利润为 32 * $3 - 8 * $8 = $32 。
9. 4 位登舱,1 位等待,摩天轮轮转。当前利润为 36 * $3 - 9 * $8 = $36 。
​​​​​​​10. 1 位登舱,0 位等待,摩天轮轮转。当前利润为 37 * $3 - 10 * $8 = $31 。
轮转 9 次得到最大利润,最大利润为 $36 。

提示

  • n == customers.length
  • 1 <= n <= 105
  • 0 <= customers[i] <= 50
  • 1 <= boardingCost, runningCost <= 100

来源:力扣(LeetCode)</br>
链接:https://leetcode-cn.com/problems/maximum-profit-of-operating-a-centennial-wheel</br>
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

这题我们的关注点其实只要关注最下面的仓位就可以,不管摩天轮如何轮转,最下面的仓位永远为空。因为转每次顾客完成一周的时候必定离开摩天轮。当我们决定停止服务时候,为了保证所有游客安全着陆,将免费进行所有后续轮转 。也就是后续费用都不在考虑范围之内。

理解了这些,这题是思路就逐渐变得清晰起来。我们只要保证每次最下面的摩天轮上的人数足够多,去除固定轮转成本,就能让我们的收益最大化。大致整理一下思路:

  • i 批游客大于4人:customer[i] - 4 人排队等待,此次利润为:4 * boardingCost - runningCost
  • i 批游客小于4人:customer[i] 人全部乘仓,此次利润为:customer[i] * boardingCost - runningCost

如果穷举情形,无非有这样几种情形

  1. customer[i] 小于等于4 全部登仓
  2. customer[i] 大于4 登仓4人,将等待人数加入customer[i+1] ,这样下次循环不影响 1 中的情形
  3. 全部遍历之后,customer[customer.length-1] 大于 4 。减去 4 个已登机人数。
  4. 对于 customer[customer.length-1] 剩下人数,尽可能每次上的最多。

最终代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Solution {

public int minOperationsMaxProfit(int[] customers, int boardingCost, int runningCost) {
int minRotaes = 0, maxProfit = 0, currentProfit = 0, currentRotaes = 0;
for (int i = 0; i < customers.length; i++) {
if (customers[i] <= 4) {
currentProfit += customers[i] * boardingCost - runningCost;
currentRotaes++;
if (maxProfit < currentProfit) {
minRotaes = currentRotaes;
maxProfit = currentProfit;
}
} else {
currentProfit += 4 * boardingCost - runningCost;
currentRotaes++;
if (maxProfit < currentProfit) {
minRotaes = currentRotaes;
maxProfit = currentProfit;
}
if (i < customers.length - 1) {
customers[i + 1] += customers[i] - 4;
}
}
}
customers[customers.length - 1] -= 4;
while (customers[customers.length - 1] > 4) {
currentProfit += 4 * boardingCost - runningCost;
currentRotaes++;
customers[customers.length - 1] -= 4;
if (maxProfit < currentProfit) {
minRotaes = currentRotaes;
maxProfit = currentProfit;
}
}
if (customers[customers.length - 1] > 0) {
currentProfit += customers[customers.length - 1] * boardingCost - runningCost;
currentRotaes++;
if (maxProfit < currentProfit) {
minRotaes = currentRotaes;
maxProfit = currentProfit;
}
}
return minRotaes > 0 ? minRotaes : -1;
}
}

结语

我以为这一题会有一些巧妙的解法,甚至去研究了一下其他人的解法。发现普遍都是把题目翻译一下,没有花哨的操作。晚点时间我找几个典型的贪心算法整理一下。


Copyright by @maybelence.

...

...

00:00
00:00