Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1176. Diet Plan Performance - Leetcode Solution

Problem Description

The Diet Plan Performance problem asks you to evaluate a person's performance on a diet by analyzing their daily calorie intake. Given an integer array calories where each element represents the calories consumed on a particular day, and three integers k, lower, and upper, your task is to:

  • Calculate the sum of calories for every consecutive sequence of k days (a sliding window of length k).
  • For each window:
    • If the sum is less than lower, decrease the performance score by 1.
    • If the sum is greater than upper, increase the performance score by 1.
    • If the sum is between lower and upper (inclusive), the score does not change.
  • Return the final performance score after evaluating all possible windows.

Constraints:

  • 1 ≤ calories.length ≤ 105
  • 1 ≤ kcalories.length
  • lower and upper can be any integers
  • Each element of calories is an integer

Thought Process

The first idea that comes to mind is to check every possible sequence of k days, sum their calories, and adjust the score accordingly. This brute-force approach would mean, for each starting index, summing up the next k elements, which could be slow if calories is large.

However, by noticing that each window overlaps with the previous one except for one element entering and one leaving, we can optimize the summing process. Instead of recalculating the sum from scratch for each window, we can keep a running sum: subtract the element that leaves the window and add the new one that enters. This is known as the sliding window technique and is much more efficient.

The key is to maintain a variable for the current sum and update it as the window slides, which reduces the time complexity from O(Nk) to O(N).

Solution Approach

Let's break down the steps for solving this problem efficiently:

  1. Initialize Variables: Start with a score variable set to 0 and a window_sum variable to keep track of the current sum.
  2. Compute Initial Window: Calculate the sum of the first k elements in calories and assign it to window_sum.
  3. Evaluate the First Window: Compare window_sum to lower and upper and update the score accordingly.
  4. Slide the Window: For each subsequent window, remove the element that's sliding out (at index i - k) and add the element that's sliding in (at index i), updating window_sum efficiently.
  5. Score Each Window: For each window, check if window_sum is less than lower, greater than upper, or in between, and update score as needed.
  6. Return the Score: After all windows have been processed, return the final score.

This approach ensures each element is only added and subtracted once, resulting in a linear time solution.

Example Walkthrough

Let's walk through an example:

  • calories = [1, 2, 3, 4, 5]
  • k = 3
  • lower = 6
  • upper = 8

Steps:

  1. First window: [1,2,3] → sum = 6
    • 6 is exactly lower, so score doesn't change (score = 0)
  2. Slide window: [2,3,4] → sum = 9 (6 - 1 + 4)
    • 9 > 8, so increment score (score = 1)
  3. Slide window: [3,4,5] → sum = 12 (9 - 2 + 5)
    • 12 > 8, so increment score (score = 2)

Final score: 2

Time and Space Complexity

Brute-force approach:

  • For each starting index, sum the next k elements: O(Nk) time, where N is the length of calories.
  • Space complexity: O(1), as only a few variables are used.
Optimized sliding window approach:
  • Each element is added and removed from the sum once: O(N) time.
  • Space complexity remains O(1).

This efficiency is achieved by not recalculating sums from scratch for overlapping windows.

Summary

The Diet Plan Performance problem is an excellent example of how the sliding window technique can optimize a seemingly expensive brute-force process. By maintaining a running sum and updating it as the window moves forward, we achieve linear time complexity. This approach is both elegant and practical, making it suitable for large input sizes. The key insight is recognizing and exploiting the overlap between consecutive windows to avoid redundant calculations.

Code Implementation

class Solution:
    def dietPlanPerformance(self, calories, k, lower, upper):
        score = 0
        window_sum = sum(calories[:k])
        n = len(calories)
        # Evaluate the first window
        if window_sum < lower:
            score -= 1
        elif window_sum > upper:
            score += 1
        # Slide the window
        for i in range(k, n):
            window_sum += calories[i] - calories[i - k]
            if window_sum < lower:
                score -= 1
            elif window_sum > upper:
                score += 1
        return score
      
class Solution {
public:
    int dietPlanPerformance(vector<int>& calories, int k, int lower, int upper) {
        int score = 0;
        int window_sum = 0;
        int n = calories.size();
        for (int i = 0; i < k; ++i) {
            window_sum += calories[i];
        }
        // Evaluate first window
        if (window_sum < lower) {
            score--;
        } else if (window_sum > upper) {
            score++;
        }
        // Slide the window
        for (int i = k; i < n; ++i) {
            window_sum += calories[i] - calories[i - k];
            if (window_sum < lower) {
                score--;
            } else if (window_sum > upper) {
                score++;
            }
        }
        return score;
    }
};
      
class Solution {
    public int dietPlanPerformance(int[] calories, int k, int lower, int upper) {
        int score = 0;
        int windowSum = 0;
        int n = calories.length;
        for (int i = 0; i < k; i++) {
            windowSum += calories[i];
        }
        // Evaluate first window
        if (windowSum < lower) {
            score--;
        } else if (windowSum > upper) {
            score++;
        }
        // Slide the window
        for (int i = k; i < n; i++) {
            windowSum += calories[i] - calories[i - k];
            if (windowSum < lower) {
                score--;
            } else if (windowSum > upper) {
                score++;
            }
        }
        return score;
    }
}
      
var dietPlanPerformance = function(calories, k, lower, upper) {
    let score = 0;
    let windowSum = 0;
    let n = calories.length;
    for (let i = 0; i < k; i++) {
        windowSum += calories[i];
    }
    // Evaluate first window
    if (windowSum < lower) {
        score--;
    } else if (windowSum > upper) {
        score++;
    }
    // Slide the window
    for (let i = k; i < n; i++) {
        windowSum += calories[i] - calories[i - k];
        if (windowSum < lower) {
            score--;
        } else if (windowSum > upper) {
            score++;
        }
    }
    return score;
};