The Grumpy Bookstore Owner problem asks you to maximize the number of satisfied customers in a bookstore over a series of minutes. You are given three inputs:
customers
: an array where customers[i]
is the number of customers that enter the store at minute i
.grumpy
: an array where grumpy[i]
is 1
if the owner is grumpy at minute i
, and 0
if not.X
: the number of consecutive minutes the owner can use a special technique to not be grumpy.
Normally, if the owner is not grumpy (grumpy[i] == 0
), all customers at that minute are satisfied. If the owner is grumpy (grumpy[i] == 1
), none of the customers at that minute are satisfied. However, the owner can use a secret technique for X
consecutive minutes to avoid being grumpy, making all customers during those minutes satisfied, regardless of the original grumpy
state.
The task is to choose the best window of X
consecutive minutes to use the technique in order to maximize the total number of satisfied customers.
Constraints:
Let's first consider the naive approach: for each possible window of X
minutes, simulate using the technique, recalculate the total satisfied customers, and pick the maximum. However, this would require recalculating the sum for each window, leading to an inefficient solution.
To optimize, notice that:
X
minutes where the sum of grumpy customers is maximized.
Let's break down the steps to solve the problem efficiently:
grumpy[i] == 0
, add customers[i]
to base_satisfied
.grumpy[i] == 1
, these customers are unsatisfied unless the technique is used.X
to sum up the number of unsatisfied customers that can be saved if the technique is used during that window.base_satisfied + max_additional_satisfied
.This approach ensures we only scan the arrays a constant number of times, making it highly efficient.
Let's use the example:
customers = [1,0,1,2,1,1,7,5]
grumpy = [0,1,0,1,0,1,0,1]
X = 3
The best window is [5,7] (minutes 5,6,7), which saves 1 (minute 5) + 0 (minute 6, not grumpy) + 5 (minute 7) = 6 customers.
class Solution:
def maxSatisfied(self, customers, grumpy, X):
base = 0
n = len(customers)
for i in range(n):
if grumpy[i] == 0:
base += customers[i]
max_extra = extra = 0
for i in range(X):
if grumpy[i]:
extra += customers[i]
max_extra = extra
for i in range(X, n):
if grumpy[i]:
extra += customers[i]
if grumpy[i-X]:
extra -= customers[i-X]
max_extra = max(max_extra, extra)
return base + max_extra
class Solution {
public:
int maxSatisfied(vector<int>& customers, vector<int>& grumpy, int X) {
int n = customers.size();
int base = 0;
for (int i = 0; i < n; ++i) {
if (grumpy[i] == 0) base += customers[i];
}
int extra = 0, max_extra = 0;
for (int i = 0; i < X; ++i) {
if (grumpy[i]) extra += customers[i];
}
max_extra = extra;
for (int i = X; i < n; ++i) {
if (grumpy[i]) extra += customers[i];
if (grumpy[i-X]) extra -= customers[i-X];
max_extra = max(max_extra, extra);
}
return base + max_extra;
}
};
class Solution {
public int maxSatisfied(int[] customers, int[] grumpy, int X) {
int n = customers.length;
int base = 0;
for (int i = 0; i < n; i++) {
if (grumpy[i] == 0) base += customers[i];
}
int extra = 0, maxExtra = 0;
for (int i = 0; i < X; i++) {
if (grumpy[i] == 1) extra += customers[i];
}
maxExtra = extra;
for (int i = X; i < n; i++) {
if (grumpy[i] == 1) extra += customers[i];
if (grumpy[i - X] == 1) extra -= customers[i - X];
maxExtra = Math.max(maxExtra, extra);
}
return base + maxExtra;
}
}
var maxSatisfied = function(customers, grumpy, X) {
let n = customers.length;
let base = 0;
for (let i = 0; i < n; i++) {
if (grumpy[i] === 0) base += customers[i];
}
let extra = 0, maxExtra = 0;
for (let i = 0; i < X; i++) {
if (grumpy[i] === 1) extra += customers[i];
}
maxExtra = extra;
for (let i = X; i < n; i++) {
if (grumpy[i] === 1) extra += customers[i];
if (grumpy[i - X] === 1) extra -= customers[i - X];
maxExtra = Math.max(maxExtra, extra);
}
return base + maxExtra;
};
Brute Force Approach:
The sliding window makes the solution efficient and suitable for large inputs.
The Grumpy Bookstore Owner problem is elegantly solved by separating always-satisfied customers from those who can be "rescued" by the owner's technique. By using a sliding window, we efficiently find the optimal window to maximize satisfaction. This approach is both fast and easy to understand, highlighting the power of breaking a problem into manageable parts and leveraging classic algorithmic techniques like the sliding window.