Medium
题目描述
有一个书店老板,他的书店开放了 n 分钟。给你一个长度为 n 的整数数组 customers,其中 customers[i] 是在第 i 分钟开始时进入商店的顾客数量,所有这些顾客都会在第 i 分钟结束后离开。
在某些时候,书店老板会生气。给你一个长度为 n 的二进制数组 grumpy,其中如果 grumpy[i] 为 1,则表示老板在第 i 分钟时生气,为 0 则表示不生气。
当书店老板生气时,那一分钟进入的顾客就会不满意,否则他们是满意的。
书店老板知道一个秘密技巧,能保持 minutes 分钟不生气,但这个技巧只能使用一次。
返回一整天中最多有多少客户能够感到满意。
示例 1:
输入:customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], minutes = 3
输出:16
解释:书店老板在最后 3 分钟保持不生气。
感到满意的最大客户数量 = 1 + 1 + 1 + 1 + 7 + 5 = 16.
示例 2:
输入:customers = [1], grumpy = [0], minutes = 1
输出:1
提示:
n == customers.length == grumpy.length1 <= minutes <= n <= 2 * 10^40 <= customers[i] <= 1000grumpy[i]是 0 或 1
解题思路
这是一个典型的滑动窗口问题。我们需要找到一个长度为 minutes 的连续时间段,在这个时间段内使用秘密技巧让老板保持不生气,使得总的满意顾客数最大。
解题思路分为两步:
计算基础满意顾客数:遍历整个数组,统计所有老板不生气时刻的顾客数量,这些顾客无论如何都会满意。
使用滑动窗口找到最佳时间段:
- 维护一个长度为
minutes的滑动窗口 - 对于窗口内每个时刻,如果老板原本生气(
grumpy[i] = 1),那么使用技巧后可以额外获得customers[i]个满意顾客 - 滑动窗口,找到能够额外获得最多满意顾客的时间段
- 维护一个长度为
具体实现时,先计算第一个窗口能额外获得的满意顾客数,然后滑动窗口:每次向右移动时,去掉左边界的贡献,加上新右边界的贡献。
最终答案 = 基础满意顾客数 + 最大额外满意顾客数。
时间复杂度为 O(n),空间复杂度为 O(1),是最优解法。
代码实现
class Solution {
public:
int maxSatisfied(vector<int>& customers, vector<int>& grumpy, int minutes) {
int n = customers.size();
// 计算基础满意顾客数(老板不生气时的顾客)
int baseSatisfied = 0;
for (int i = 0; i < n; i++) {
if (grumpy[i] == 0) {
baseSatisfied += customers[i];
}
}
// 计算第一个窗口内能额外获得的满意顾客数
int extraSatisfied = 0;
for (int i = 0; i < minutes; i++) {
if (grumpy[i] == 1) {
extraSatisfied += customers[i];
}
}
// 滑动窗口找到最大额外满意顾客数
int maxExtraSatisfied = extraSatisfied;
for (int i = minutes; i < n; i++) {
// 移除窗口左边界的贡献
if (grumpy[i - minutes] == 1) {
extraSatisfied -= customers[i - minutes];
}
// 添加新的右边界贡献
if (grumpy[i] == 1) {
extraSatisfied += customers[i];
}
maxExtraSatisfied = max(maxExtraSatisfied, extraSatisfied);
}
return baseSatisfied + maxExtraSatisfied;
}
};
class Solution:
def maxSatisfied(self, customers: List[int], grumpy: List[int], minutes: int) -> int:
n = len(customers)
# 计算基础满意顾客数(老板不生气时的顾客)
base_satisfied = sum(customers[i] for i in range(n) if grumpy[i] == 0)
# 计算第一个窗口内能额外获得的满意顾客数
extra_satisfied = sum(customers[i] for i in range(minutes) if grumpy[i] == 1)
# 滑动窗口找到最大额外满意顾客数
max_extra_satisfied = extra_satisfied
for i in range(minutes, n):
# 移除窗口左边界的贡献
if grumpy[i - minutes] == 1:
extra_satisfied -= customers[i - minutes]
# 添加新的右边界贡献
if grumpy[i] == 1:
extra_satisfied += customers[i]
max_extra_satisfied = max(max_extra_satisfied, extra_satisfied)
return base_satisfied + max_extra_satisfied
public class Solution {
public int MaxSatisfied(int[] customers, int[] grumpy, int minutes) {
int n = customers.Length;
// 计算基础满意顾客数(老板不生气时的顾客)
int baseSatisfied = 0;
for (int i = 0; i < n; i++) {
if (grumpy[i] == 0) {
baseSatisfied += customers[i];
}
}
// 计算第一个窗口内能额外获得的满意顾客数
int extraSatisfied = 0;
for (int i = 0; i < minutes; i++) {
if (grumpy[i] == 1) {
extraSatisfied += customers[i];
}
}
// 滑动窗口找到最大额外满意顾客数
int maxExtraSatisfied = extraSatisfied;
for (int i = minutes; i < n; i++) {
// 移除窗口左边界的贡献
if (grumpy[i - minutes] == 1) {
extraSatisfied -= customers[i - minutes];
}
// 添加新的右边界贡献
if (grumpy[i] == 1) {
extraSatisfied += customers[i];
}
maxExtraSatisfied = Math.Max(maxExtraSatisfied, extraSatisfied);
}
return baseSatisfied + maxExtraSatisfied;
}
}
var maxSatisfied = function(customers, grumpy, minutes) {
const n = customers.length;
// 计算基础满意顾客数(老板不生气时的顾客)
let baseSatisfied = 0;
for (let i = 0; i < n; i++) {
if (grumpy[i]
复杂度分析
| 复杂度类型 | 值 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 需要遍历数组两次,一次计算基础满意顾客数,一次滑动窗口 |
| 空间复杂度 | O(1) | 只使用常数额外空间 |