Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1052. Grumpy Bookstore Owner - Leetcode Solution

Problem Description

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:

  • One valid solution exists for all inputs.
  • Do not reuse elements outside the selected technique window.
  • All input arrays have the same length.

Thought Process

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:

  • Customers during non-grumpy minutes are always satisfied, regardless of the technique.
  • The only customers we can "save" with the technique are those during grumpy minutes.
  • We want to maximize the number of grumpy customers we convert to satisfied ones by applying the technique to the window with the most grumpy customers.
This insight suggests using a sliding window to efficiently find the best window of X minutes where the sum of grumpy customers is maximized.

Solution Approach

Let's break down the steps to solve the problem efficiently:

  1. Calculate Satisfied Customers Without the Technique:
    • Iterate through each minute.
    • If grumpy[i] == 0, add customers[i] to base_satisfied.
  2. Identify Customers That Can Be Saved:
    • For each minute where grumpy[i] == 1, these customers are unsatisfied unless the technique is used.
  3. Use Sliding Window to Find the Optimal Technique Window:
    • Use a window of size X to sum up the number of unsatisfied customers that can be saved if the technique is used during that window.
    • Slide the window across the array, updating the sum efficiently by adding the new rightmost element and removing the leftmost.
    • Track the maximum number of customers that can be saved in any window.
  4. Combine Results:
    • The final answer is base_satisfied + max_additional_satisfied.

This approach ensures we only scan the arrays a constant number of times, making it highly efficient.

Example Walkthrough

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

  1. Calculate Base Satisfied:
    • Minutes 0,2,4,6: grumpy = 0, so sum = 1 + 1 + 1 + 7 = 10
  2. Sliding Window of Size 3:
    • Window [0,2]: Only minute 1 is grumpy, so sum = 0 (minute 0) + 0 (minute 1, grumpy=1, customers=0) + 0 (minute 2, grumpy=0)
    • Window [1,3]: Minutes 1 and 3 are grumpy, sum = 0 (minute 1, customers=0) + 0 (minute 2, grumpy=0) + 2 (minute 3, grumpy=1) = 2
    • Window [2,4]: Minute 3 is grumpy, sum = 0 + 2 + 0 = 2
    • Window [3,5]: Minutes 3 and 5 are grumpy, sum = 2 (minute 3) + 0 (minute 4, grumpy=0) + 1 (minute 5, grumpy=1) = 3
    • Window [4,6]: Minute 5 is grumpy, sum = 0 + 1 + 0 = 1
    • Window [5,7]: Minutes 5 and 7 are grumpy, sum = 1 (minute 5) + 0 (minute 6, grumpy=0) + 5 (minute 7, grumpy=1) = 6

    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.

  3. Final Answer:
    • Base satisfied: 10
    • Max additional: 6
    • Total: 16

Code Implementation

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;
};
      

Time and Space Complexity

Brute Force Approach:

  • For each possible window (O(n)), sum up the satisfied customers (O(n) per window).
  • Total time complexity: O(n^2).
  • Space complexity: O(1), as no extra data structures are needed.
Optimized Sliding Window Approach:
  • We scan the arrays a constant number of times (for base and for the window).
  • Total time complexity: O(n), since each element is processed at most twice.
  • Space complexity: O(1), as only a few variables are used.

The sliding window makes the solution efficient and suitable for large inputs.

Summary

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.