有一个书店老板,他的书店开了 n
分钟。每分钟都有一些顾客进入这家商店。给定一个长度为 n
的整数数组 customers
,其中 customers[i]
是在第 i
分钟开始时进入商店的顾客数量,所有这些顾客在第 i
分钟结束后离开。
在某些时候,书店老板会生气。 如果书店老板在第 i
分钟生气,那么 grumpy[i] = 1
,否则 grumpy[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.length
1 <= minutes <= n <= 2 * 10^4
0 <= customers[i] <= 1000
grumpy[i] == 0 or 1
老板的奇技淫巧
如果老板没有秘密技巧,那么当天满意的客户数量就是老板不生气的时间乘上对应时间的客户数量的累加:
分析关键点如下:
- 老板的秘密技巧只能将生气变为不生气,体现在结果上,对grumpy数组中为0的下标无影响,也就是说,可以先计算本来就满意的客户,这部分不受秘密技巧影响。
for (int i = 0; i < n; i++) { if (grumpy[i] == 0) { satisfy += customers[i]; } }
- 为了便于理解,在上述计算satisfy的过程中,将已经计算过的customers[ i ]置为0(实际编码中无需如此)。
- 在此基础上,问题就转化成了,在customers数组中,找到一个连续的、长度为minutes的数组,使得它包含的数的和最大。
这个问题就是标准的定长滑动窗口问题。
继续以上述示例1为例:
定义extra为对当前窗口使用秘密技巧相比不使用技巧增加的满意客户数量。
由于grumpy中为0(即不生气的部分已经计算过)所以在滑动过程中,只关心1(生气)的部分。
上图是窗口增长到minutes大小的过程。因为在下标为1的时刻客户数是0,所以即使不生气也不增加客户数。
当窗口长度等于minutes大小,接下来就是滑动过程,滑动过程中需要计算当前窗口的extra值,维护extra的最大值。
当滑动到数组尾时,extra的最大值加上satisfy就是这一天营业下来,最多满意客户的数量。
到这里整个思路就已经完善了,当然可以按照上面的过程,写两个for循环,一个计算satisfy,一个维护extra。但实际上不需要去修改原customer数组,并且在一个循环内就能求解:
for(int i = 0;i < n;++i){
if(grumpy[i] == 0){
satisfy += customers[i];
}else{
angry += customers[i];
}
if(i < minutes-1){
continue;
}
max_a = max(max_a,angry);
angry = angry - (grumpy[i - minutes + 1] ? customers[i - minutes + 1] : 0);
}
这里采取了后置滑动,也就是先删除再加入的过程。(循环内的后半部分和下一次循环的前半部构成一个窗口)
在每次循环中根据grumpy的值,计算当前客户应该加入satisfy还是extra,利用:
if(i < minutes-1){
continue;
}
增长窗口大小,当窗口大小等于minutes时,进行滑动。
在删除窗口头部元素时,判断grumpy的值是否为1(生气),即只有生气时对应的客户才会增加extra,忽略掉了grumpy[ i ] = 0时的客户,因为已经加入了satisfy中。
这个过程等价于上文将grumpy[ i ] = 0时对应的costomer数组值置为0。
完整代码:
class Solution {
public:
int maxSatisfied(vector<int>& customers, vector<int>& grumpy, int minutes) {
int satisfy = 0;
int angry = 0;
int max_a = 0;
int n = customers.size();
for(int i = 0;i < n;++i){
if(grumpy[i] == 0){
satisfy += customers[i];
}else{
angry += customers[i];
}
if(i < minutes-1){
continue;
}
max_a = max(max_a,angry);
angry = angry - (grumpy[i - minutes + 1] ? customers[i - minutes + 1] : 0);
}
return satisfy + max_a;
}
};