Medium
题目描述
你是一座百年摩天轮的操作员,该摩天轮有四个缆车厢,每个缆车厢最多可以容纳四人。你有能力逆时针旋转缆车厢,每次旋转需要花费 runningCost 美元。
给你一个长度为 n 的数组 customers,其中 customers[i] 表示在第 i 次旋转(从 0 开始计数)之前到达的新顾客数量。这意味着在 customers[i] 个顾客到达之前,你必须旋转摩天轮 i 次。如果缆车厢有空间,你不能让顾客等待。每个顾客在登上距离地面最近的缆车厢时支付 boardingCost 美元,并在该缆车厢再次到达地面时下车。
你可以随时停止摩天轮,包括在服务所有顾客之前。如果你决定停止服务顾客,所有后续的旋转都是免费的,以便让所有顾客安全下车。注意,如果当前有超过四个顾客在摩天轮旁等待,只有四个会登上缆车厢,其余的将等待下一次旋转。
返回使你的利润最大化所需执行的最小旋转次数。如果没有任何情况可以产生正利润,返回 -1。
示例 1:
输入:customers = [8,3], boardingCost = 5, runningCost = 6
输出:3
示例 2:
输入:customers = [10,9,6], boardingCost = 6, runningCost = 4
输出:7
示例 3:
输入:customers = [3,4,0,5,1], boardingCost = 1, runningCost = 92
输出:-1
约束条件:
n == customers.length1 <= n <= 10^50 <= customers[i] <= 501 <= boardingCost, runningCost <= 100
解题思路
这是一道模拟题,需要我们模拟摩天轮的运转过程。
解题思路:
模拟过程:我们需要逐步模拟摩天轮的每一次旋转,跟踪等待的顾客数量、已上车的顾客总数和当前利润。
关键变量:
waiting:当前等待的顾客数量totalCustomers:总共上车的顾客数量profit:当前利润maxProfit:最大利润bestRotation:获得最大利润时的旋转次数
模拟步骤:
- 处理所有输入的顾客到达时间
- 每次旋转时,最多4个顾客上车
- 更新利润 = 上车顾客数 × boardingCost - runningCost
- 记录最大利润对应的旋转次数
继续旋转的条件:即使处理完所有输入顾客,如果还有等待的顾客,需要继续旋转。但要注意,如果每次旋转的收益(4 × boardingCost - runningCost)为负,就不应该继续。
优化点:当等待顾客数量不足4人且继续旋转会亏损时,应该停止模拟。
这个问题的核心是要找到利润最大化的旋转次数,需要考虑所有可能的停止点。
代码实现
class Solution {
public:
int minOperationsMaxProfit(vector<int>& customers, int boardingCost, int runningCost) {
int waiting = 0;
int totalCustomers = 0;
int profit = 0;
int maxProfit = 0;
int bestRotation = -1;
int rotation = 0;
// 处理所有顾客到达的时间点
for (int i = 0; i < customers.size(); i++) {
waiting += customers[i];
// 每次旋转最多4人上车
int boarding = min(waiting, 4);
waiting -= boarding;
totalCustomers += boarding;
// 计算利润
profit = totalCustomers * boardingCost - (i + 1) * runningCost;
if (profit > maxProfit) {
maxProfit = profit;
bestRotation = i + 1;
}
}
// 继续处理剩余等待的顾客
while (waiting > 0) {
rotation++;
int boarding = min(waiting, 4);
waiting -= boarding;
totalCustomers += boarding;
profit = totalCustomers * boardingCost - (customers.size() + rotation) * runningCost;
if (profit > maxProfit) {
maxProfit = profit;
bestRotation = customers.size() + rotation;
}
// 如果继续旋转只会亏损,提前结束
if (4 * boardingCost < runningCost) {
break;
}
}
return bestRotation;
}
};
class Solution:
def minOperationsMaxProfit(self, customers: List[int], boardingCost: int, runningCost: int) -> int:
waiting = 0
total_customers = 0
profit = 0
max_profit = 0
best_rotation = -1
rotation = 0
# 处理所有顾客到达的时间点
for i in range(len(customers)):
waiting += customers[i]
# 每次旋转最多4人上车
boarding = min(waiting, 4)
waiting -= boarding
total_customers += boarding
# 计算利润
profit = total_customers * boardingCost - (i + 1) * runningCost
if profit > max_profit:
max_profit = profit
best_rotation = i + 1
# 继续处理剩余等待的顾客
while waiting > 0:
rotation += 1
boarding = min(waiting, 4)
waiting -= boarding
total_customers += boarding
profit = total_customers * boardingCost - (len(customers) + rotation) * runningCost
if profit > max_profit:
max_profit = profit
best_rotation = len(customers) + rotation
# 如果继续旋转只会亏损,提前结束
if 4 * boardingCost < runningCost:
break
return best_rotation
public class Solution {
public int MinOperationsMaxProfit(int[] customers, int boardingCost, int runningCost) {
int waiting = 0;
int totalCustomers = 0;
int profit = 0;
int maxProfit = 0;
int bestRotation = -1;
int rotation = 0;
// 处理所有顾客到达的时间点
for (int i = 0; i < customers.Length; i++) {
waiting += customers[i];
// 每次旋转最多4人上车
int boarding = Math.Min(waiting, 4);
waiting -= boarding;
totalCustomers += boarding;
// 计算利润
profit = totalCustomers * boardingCost - (i + 1) * runningCost;
if (profit > maxProfit) {
maxProfit = profit;
bestRotation = i + 1;
}
}
// 继续处理剩余等待的顾客
while (waiting > 0) {
rotation++;
int boarding = Math.Min(waiting, 4);
waiting -= boarding;
totalCustomers += boarding;
profit = totalCustomers * boardingCost - (customers.Length + rotation) * runningCost;
if (profit > maxProfit) {
maxProfit = profit;
bestRotation = customers.Length + rotation;
}
// 如果继续旋转只会亏损,提前结束
if (4 * boardingCost < runningCost) {
break;
}
}
return bestRotation;
}
}
var minOperationsMaxProfit = function(customers, boardingCost, runningCost) {
let waiting = 0;
let totalCustomers = 0;
let profit = 0;
let maxProfit = 0;
let bestRotation = -1;
let rotation = 0;
// 处理所有顾客到达的时间点
for (let i = 0; i < customers.length; i++) {
waiting += customers[i];
// 每次旋转最多4人上车
const boarding = Math.min(waiting, 4);
waiting -= boarding;
totalCustomers += boarding;
// 计算利润
profit = totalCustomers * boardingCost - (i + 1) * runningCost;
if (profit > maxProfit) {
maxProfit = profit;
bestRotation = i + 1;
}
}
// 继续处理剩余等待的顾客
while (waiting > 0) {
rotation++;
const boarding = Math.min(waiting, 4);
waiting -= boarding;
totalCustomers += boarding;
profit = totalCustomers * boardingCost - (customers.length + rotation) * runningCost;
if (profit > maxProfit) {
maxProfit = profit;
bestRotation = customers.length + rotation;
}
// 如果继续旋转只会亏损,提前结束
if (4 * boardingCost < runningCost) {
break;
}
}
return bestRotation;
};
复杂度分析
| 复杂度类型 | 分析 |
|---|---|
| 时间复杂度 | O(n + w/4),其中 n 是 customers 数组长度,w 是最大等待人数。由于每个顾客最多等待 50 人,最坏情况是 O(n + 50n/4) = O(n) |
| 空间复杂度 | O(1),只使用了常数个变量存储状态 |