LeetCode 1176 - Diet Plan Performance
The problem is asking us to simulate a dieter’s performance over a sequence of days based on their calorie consumption. The input is an array calories where calories[i] represents the number of calories consumed on day i. We are also given three integers: k, lower, and upper.
Difficulty: 🟢 Easy
Topics: Array, Sliding Window
Solution
Problem Understanding
The problem is asking us to simulate a dieter’s performance over a sequence of days based on their calorie consumption. The input is an array calories where calories[i] represents the number of calories consumed on day i. We are also given three integers: k, lower, and upper. For every consecutive sequence of k days, we calculate the total calories T. The rules for scoring are simple: if T < lower, the dieter loses 1 point; if T > upper, they gain 1 point; otherwise, there is no change in points. The goal is to calculate the total points after evaluating all possible consecutive sequences of length k.
The constraints indicate that k will always be at least 1 and at most the length of the calories array, which itself can be up to 10^5. Each calorie count is non-negative and bounded by 20,000. The lower and upper thresholds are also non-negative and lower will not exceed upper. This suggests that the solution must efficiently handle large arrays, and brute-force approaches that recompute sums for all subarrays could be too slow. Edge cases to consider include very small arrays, k equal to the array length, sequences where all elements are equal, and scenarios where all subarrays are exactly at the lower or upper thresholds.
Approaches
The brute-force approach involves iterating through every possible subarray of length k and computing its sum. Once the sum is calculated, it is compared to lower and upper to adjust the points accordingly. While this approach is straightforward and correct, it is inefficient because computing the sum of a length-k subarray for each starting index i requires O(k) time. With n elements, this results in O(n*k) time complexity, which is too slow for n up to 100,000.
The key observation for optimization is that we can maintain a running sum of length k using a sliding window. Instead of recomputing the sum for each subarray from scratch, we initialize the sum for the first k elements and then slide the window one element at a time: subtract the element leaving the window and add the element entering the window. This allows each sum calculation to be done in O(1) time, reducing the overall complexity to O(n). This technique is applicable because consecutive subarrays overlap significantly, so reusing previous computations is efficient.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n*k) | O(1) | Calculate sum of each subarray independently |
| Optimal | O(n) | O(1) | Sliding window approach for consecutive sums |
Algorithm Walkthrough
- Initialize two variables:
pointsto 0 to keep track of the score, andwindow_sumto 0 to store the sum of the current window of sizek. - Compute the sum of the first
kelements and store it inwindow_sum. Comparewindow_sumtolowerandupperand adjustpointsaccording to the rules. - Slide the window through the array starting from index
kto the end. For each new element entering the window, add it towindow_sumand subtract the element leaving the window (which iscalories[i-k]). - After updating
window_sum, compare it tolowerandupper. Ifwindow_sum < lower, decrementpointsby 1. Ifwindow_sum > upper, incrementpointsby 1. Otherwise, do nothing. - Continue until the window reaches the end of the array.
- Return the final
pointsvalue.
Why it works: At each step, the window sum represents exactly the sum of k consecutive days. The sliding window ensures that every possible subarray of length k is evaluated exactly once. The score updates according to the problem rules, so the final points value is guaranteed to be correct.
Python Solution
from typing import List
class Solution:
def dietPlanPerformance(self, calories: List[int], k: int, lower: int, upper: int) -> int:
points = 0
window_sum = sum(calories[:k])
if window_sum < lower:
points -= 1
elif window_sum > upper:
points += 1
for i in range(k, len(calories)):
window_sum += calories[i] - calories[i - k]
if window_sum < lower:
points -= 1
elif window_sum > upper:
points += 1
return points
The implementation initializes the points counter and calculates the initial sum for the first k days. It then slides the window through the array, updating the sum in O(1) time for each new position. The score is adjusted immediately after each window update, ensuring the final score accurately reflects all subarrays of length k.
Go Solution
func dietPlanPerformance(calories []int, k int, lower int, upper int) int {
points := 0
windowSum := 0
for i := 0; i < k; i++ {
windowSum += calories[i]
}
if windowSum < lower {
points--
} else if windowSum > upper {
points++
}
for i := k; i < len(calories); i++ {
windowSum += calories[i] - calories[i-k]
if windowSum < lower {
points--
} else if windowSum > upper {
points++
}
}
return points
}
The Go implementation mirrors the Python version. Go handles slices similarly to Python lists, so the sliding window logic is identical. There are no concerns with nil slices since the problem guarantees k >= 1. Integer overflow is not a concern due to the constraints on calories[i] and k.
Worked Examples
Example 1: calories = [1,2,3,4,5], k = 1, lower = 3, upper = 3
| i | window_sum | points update | points |
|---|---|---|---|
| 0 | 1 | < lower | -1 |
| 1 | 2 | < lower | -2 |
| 2 | 3 | in range | -2 |
| 3 | 4 | > upper | -1 |
| 4 | 5 | > upper | 0 |
Final points: 0
Example 2: calories = [3,2], k = 2, lower = 0, upper = 1
| i | window_sum | points update | points |
|---|---|---|---|
| 0 | 5 | > upper | 1 |
Final points: 1
Example 3: calories = [6,5,0,0], k = 2, lower = 1, upper = 5
| i | window_sum | points update | points |
|---|---|---|---|
| 0 | 11 | > upper | 1 |
| 1 | 5 | in range | 1 |
| 2 | 0 | < lower | 0 |
Final points: 0
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Sliding window sums are updated in O(1) per step for n elements |
| Space | O(1) | Only a few integer variables are used, no extra data structures |
The algorithm is efficient because it avoids recomputing sums for overlapping subarrays, leveraging the overlap to achieve linear time.
Test Cases
# Example tests
assert Solution().dietPlanPerformance([1,2,3,4,5], 1, 3, 3) == 0 # mixed below and above
assert Solution().dietPlanPerformance([3,2], 2, 0, 1) == 1 # total > upper
assert Solution().dietPlanPerformance([6,5,0,0], 2, 1, 5) == 0 # mixed cases
# Edge cases
assert Solution().dietPlanPerformance([0], 1, 0, 0) == 0 # single element exactly at threshold
assert Solution().dietPlanPerformance([10**4]*10**5, 10**5, 50000, 2000000) == 1 # large input
assert Solution().dietPlanPerformance([1,1,1,1], 4, 5, 5) == -1 # sum < lower
assert Solution().dietPlanPerformance([5,5,5,5], 4, 5, 5) == 0 # sum == threshold
assert Solution().dietPlanPerformance([10,10,10,10], 4, 5, 20) == 1 # sum > upper
| Test | Why |
|---|---|
[1,2,3,4,5], k=1 |
Tests single-day windows with mixed below/above |
[3,2], k=2 |
Tests multi-day window where sum exceeds upper |
[6,5,0,0], k=2 |
Mixed cases including exact lower and upper checks |