爱生气的书店老板

题目描述

1052. 爱生气的书店老板 难度:中等-简单

   今天,书店老板有一家店打算试营业 customers.length 分钟。每分钟都有一些顾客(customers[i])会进入书店,所有这些顾客都会在那一分钟结束后离开。

在某些时候,书店老板会生气。 如果书店老板在第 i 分钟生气,那么 grumpy[i] = 1,否则 grumpy[i] = 0。 当书店老板生气时,那一分钟的顾客就会不满意,不生气则他们是满意的。

书店老板知道一个秘密技巧,能抑制自己的情绪,可以让自己连续 X 分钟不生气,但却只能使用一次。

请你返回这一天营业下来,最多有多少客户能够感到满意的数量。

示例:

输入:customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], X = 3
输出:16
解释:
书店老板在最后 3 分钟保持冷静。
感到满意的最大客户数量 = 1 + 1 + 1 + 1 + 7 + 5 = 16.

提示:

1 <= X <= customers.length == grumpy.length <= 20000
0 <= customers[i] <= 1000
0 <= grumpy[i] <= 1

 题解代码

暴力解法

 1 class Solution {
 2     public int maxSatisfied(int[] customers, int[] grumpy, int X) {
 3         int maxSatisfied = 0;
 4         for(int i = 0;i<=customers.length-X;i++){
 5             int curSatisfied=0;
 6             for(int j = 0;j<i;j++){//连续不生气之前
 7                 curSatisfied+=customers[j]*(1-grumpy[j]);
 8             }
 9             for(int j=i;j<=i+X-1;j++){//连续不生气
10                 curSatisfied+=customers[j];
11             }
12             for(int j=i+X;j<customers.length;j++){//连续不生气之后
13                 curSatisfied+=customers[j]*(1-grumpy[j]);
14             }
15             maxSatisfied=Math.max(maxSatisfied,curSatisfied);
16         }
17         return maxSatisfied;
18     }
19 }

暴力解法思路很简单,只是在grumpy数组上滑窗长度为X的区间,作为连续不生气的时间区间。

 观察发现暴力解法每次都统计整个数组的和,但其实对于没有使用技巧的和,使用技巧后的和只是改变了长度为X的滑动窗口的部分和,因此可以先求出整个数组的和,再计算滑动窗口内翻转的部分和的最大值,于是就有了下面的优化解法。

优化解法

 1 class Solution {
 2     public int maxSatisfied(int[] customers, int[] grumpy, int X) {
 3         int allSatisNum = 0;
 4         for(int i=0;i<customers.length;i++){
 5             allSatisNum += customers[i]*(grumpy[i]^1);//统计没有使用秘密技巧时满意的人数总和
 6         }
 7         int curExtraNum = 0;
 8         int maxExtraNum = 0;
 9         for(int i=0;i<X;i++){//计算首个滑动窗口的翻转部分和
10             curExtraNum += customers[i]*grumpy[i];
11         }
12         maxExtraNum = curExtraNum;
13         for(int i=X;i<customers.length;i++){//滑动窗口
14             curExtraNum += customers[i]*grumpy[i];//加上滑动窗口右移新添的
15             curExtraNum -= customers[i-X]*grumpy[i-X];//减去滑动窗口右移抛弃的
16             maxExtraNum = Math.max(curExtraNum,maxExtraNum);//更新翻转部分和的最大值
17         }
18         return allSatisNum + maxExtraNum;
19     }
20 }

 进一步优化

仔细观察发现,上述解法对customers数组进行了两次互不干扰的遍历,因此,两次遍历可以合为一次。

 1 class Solution {
 2     public int maxSatisfied(int[] customers, int[] grumpy, int X) {
 3         int allSatisNum = 0;
 4         int curExtraNum = 0;
 5         int maxExtraNum = 0;
 6         for(int i=0;i<customers.length;i++){
 7             allSatisNum += customers[i]*(grumpy[i]^1);//统计没有使用秘密技巧时满意的人数总和
 8             if(i<X){//计算首个滑动窗口的翻转部分和
 9                 curExtraNum += customers[i]*grumpy[i];
10                 maxExtraNum = curExtraNum;
11             }else{
12                 curExtraNum += customers[i]*grumpy[i];//加上滑动窗口右移新添的
13                 curExtraNum -= customers[i-X]*grumpy[i-X];//减去滑动窗口右移抛弃的
14                 if(curExtraNum>maxExtraNum){
15                     maxExtraNum = curExtraNum;//更新翻转部分和的最大值
16                 }
17             }
18         }
19         return allSatisNum + maxExtraNum;
20     }
21 }

 

posted @ 2021-02-24 15:31  HickeyZhang  阅读(71)  评论(0)    收藏  举报