3687. Library Late Fee Calculator 🔒
Problem Description
You are given an integer array daysLate, where each element daysLate[i] tells you how many days late the i-th book was returned to the library.
Each book incurs a penalty (late fee) based on how late it was returned:
- If the book is exactly 1 day late (
daysLate[i] == 1), the penalty is1. - If the book is between 2 and 5 days late (inclusive), the penalty is
2 * daysLate[i]. - If the book is more than 5 days late (
daysLate[i] > 5), the penalty is3 * daysLate[i].
Your task is to compute the penalty for every book in the array and return the total penalty for all books combined.
Example:
If daysLate = [1, 3, 6]:
- The first book is 1 day late, so its penalty is
1. - The second book is 3 days late, so its penalty is
2 * 3 = 6. - The third book is 6 days late, so its penalty is
3 * 6 = 18.
The total penalty is 1 + 6 + 18 = 25.
How We Pick the Algorithm
Why Simulation / Basic DSA?
This problem maps to Simulation / Basic DSA through a short path in the full flowchart.
The problem directly computes penalties per book based on simple threshold rules (1 day, 2-5 days, >5 days) and sums them.
Open in FlowchartIntuition
The problem directly tells us how to calculate the penalty for each book — there is no hidden trick or optimization needed. This is a classic simulation problem: we just follow the rules as stated.
The key observation is that each book's penalty depends only on its own lateness, not on any other book. This independence means we can:
- Process each element of
daysLateone by one. - Apply the correct penalty rule based on which range the value falls into.
- Add up all the individual penalties.
Since the penalty rules form three distinct cases, it's natural to express them as a piecewise function:
f(x) = 1 when x == 1, f(x) = 2x when 2 <= x <= 5, and f(x) = 3x when x > 5.
Once we have this helper function, the answer is simply the sum of f(x) over every x in the array. A single pass through the array is enough, giving us a straightforward linear-time solution.
Solution Approach
We use simulation to directly translate the penalty rules into code.
Step 1: Define the penalty function
We define a helper function f(x) that computes the late fee for a single book based on how many days late it is:
f(x) = 1 if x = 1
f(x) = 2x if 2 <= x <= 5
f(x) = 3x if x > 5
In the code, this is implemented with simple conditional checks:
def f(x: int) -> int:
if x == 1:
return 1
if x > 5:
return 3 * x
return 2 * x
Note the ordering of the checks:
- First, we check
x == 1and return1. - Next, we check
x > 5and return3 * x. - If neither condition holds,
xmust be in the range[2, 5], so we return2 * x— no explicit range check is needed.
Step 2: Sum the penalties
Since each book's penalty is independent, we iterate through every element x in daysLate, apply f(x), and accumulate the results:
return sum(f(x) for x in daysLate)
This uses a generator expression with Python's built-in sum, which processes the array in a single pass without building any intermediate list.
Complexity Analysis
- Time complexity:
O(n), wherenis the length ofdaysLate. Each element is visited exactly once, and computingf(x)takes constant time. - Space complexity:
O(1). Only a constant amount of extra space is used, since the generator expression does not materialize a new list.
Example Walkthrough
Let's trace the solution with daysLate = [4, 1, 7, 2].
We process each element one by one, applying the penalty function f(x), and keep a running total:
Step 1: x = 4
- Is
x == 1? No. - Is
x > 5? No. - Neither condition holds, so
xfalls in the range[2, 5]→ penalty =2 * 4 = 8. - Running total:
8.
Step 2: x = 1
- Is
x == 1? Yes → penalty =1. - Running total:
8 + 1 = 9.
Step 3: x = 7
- Is
x == 1? No. - Is
x > 5? Yes → penalty =3 * 7 = 21. - Running total:
9 + 21 = 30.
Step 4: x = 2
- Is
x == 1? No. - Is
x > 5? No. xis in[2, 5]→ penalty =2 * 2 = 4.- Running total:
30 + 4 = 34.
Result: After a single pass through the array, the accumulated sum is 34, which is the total penalty returned by sum(f(x) for x in daysLate).
| Index | daysLate[i] | Rule Applied | Penalty | Running Total |
|---|---|---|---|---|
| 0 | 4 | 2 <= x <= 5 → 2x | 8 | 8 |
| 1 | 1 | x == 1 → 1 | 1 | 9 |
| 2 | 7 | x > 5 → 3x | 21 | 30 |
| 3 | 2 | 2 <= x <= 5 → 2x | 4 | 34 |
This walkthrough highlights the two core ideas of the approach: each book's penalty is computed independently through the piecewise function, and the final answer is just the accumulation of those values in one linear scan.
Solution Implementation
1class Solution:
2 def lateFee(self, daysLate: List[int]) -> int:
3 # Calculate the fee for a single book based on how many days it is late
4 def calculate_fee(days: int) -> int:
5 # Exactly 1 day late: flat fee of 1
6 if days == 1:
7 return 1
8 # More than 5 days late: fee is 3 per day
9 if days > 5:
10 return 3 * days
11 # Between 2 and 5 days late (inclusive): fee is 2 per day
12 return 2 * days
13
14 # Sum up the fees for all books
15 return sum(calculate_fee(days) for days in daysLate)
16```
17
18**Explanation of the changes:**
19
201. **Naming**: The helper function `f` was renamed to `calculate_fee`, and its parameter `x` was renamed to `days` — both follow Python's `snake_case` convention and clearly convey intent. The method name `lateFee` and parameter `daysLate` were kept unchanged as required (they match LeetCode's signature).
21
222. **Comments**: Each branch of the fee logic is documented, making the tiered pricing rules (1 day → flat 1, 2–5 days → 2/day, 6+ days → 3/day) immediately clear to readers.
23
243. **Logic**: The algorithm itself is already optimal — a single O(n) pass with O(1) extra space — so no structural changes were needed.
25
26**Alternative approach** — if you prefer a more compact, expression-based style, the same logic can be written with a conditional expression:
27
28```python3
29class Solution:
30 def lateFee(self, daysLate: List[int]) -> int:
31 # 1 day late costs 1; 2-5 days cost 2 per day; 6+ days cost 3 per day
32 return sum(1 if d == 1 else 2 * d if d <= 5 else 3 * d for d in daysLate)
331class Solution {
2 /**
3 * Calculates the total late fee for all overdue items.
4 *
5 * Fee rules per item:
6 * - Exactly 1 day late: fee is 1
7 * - 2 to 5 days late: fee is 2 * daysLate
8 * - More than 5 days: fee is 3 * daysLate
9 *
10 * @param daysLate array where each element is the number of days an item is late
11 * @return the sum of late fees for all items
12 */
13 public int lateFee(int[] daysLate) {
14 int totalFee = 0;
15
16 // Accumulate the fee for each overdue item
17 for (int days : daysLate) {
18 if (days == 1) {
19 // Late by exactly one day: flat fee of 1
20 totalFee += 1;
21 } else if (days > 5) {
22 // Late by more than five days: triple rate
23 totalFee += 3 * days;
24 } else {
25 // Late by 2 to 5 days: double rate
26 totalFee += 2 * days;
27 }
28 }
29
30 return totalFee;
31 }
32}
33```
34
35Key changes made:
36
371. **Removed the `IntUnaryOperator` lambda** — replaced it with a straightforward `if-else` chain inside the loop. This avoids the functional-interface overhead and keeps the logic inline, which is simpler and more idiomatic for such a small computation.
382. **Standardized naming** — `ans` became `totalFee` (describes what it holds), and the loop variable `x` became `days` (describes what it represents). The method name `lateFee` is preserved.
393. **Added comments** — a Javadoc block documents the fee rules and parameters, and inline comments explain each branch.
40
41An alternative perspective: if you prefer keeping the functional style, you could use a stream-based one-liner instead:
42
43```java
44class Solution {
45 public int lateFee(int[] daysLate) {
46 // Map each overdue duration to its fee, then sum them all
47 return java.util.Arrays.stream(daysLate)
48 .map(days -> days == 1 ? 1 : days > 5 ? 3 * days : 2 * days)
49 .sum();
50 }
51}
521class Solution {
2public:
3 int lateFee(vector<int>& daysLate) {
4 // Lambda function to calculate the fee for a single rental
5 // based on the number of days it is late.
6 auto calculateFee = [](int days) {
7 if (days == 1) {
8 // Late by exactly 1 day: flat fee of 1
9 return 1;
10 } else if (days > 5) {
11 // Late by more than 5 days: fee is 3 per day
12 return 3 * days;
13 } else {
14 // Late by 2 to 5 days: fee is 2 per day
15 return 2 * days;
16 }
17 };
18
19 int totalFee = 0;
20 // Accumulate the fee for each late rental
21 for (int days : daysLate) {
22 totalFee += calculateFee(days);
23 }
24 return totalFee;
25 }
26};
27```
28
29**Explanation of the changes:**
30
311. **Standardized naming**:
32 - `f` → `calculateFee`: describes the lambda's purpose clearly.
33 - `x` → `days`: conveys that the variable represents days late.
34 - `ans` → `totalFee`: indicates it holds the accumulated result.
35 - The method name `lateFee` remains unchanged as required.
36
372. **Comments added**: Each branch of the fee logic and the accumulation loop is documented, making the tiered pricing structure (1 day / 2–5 days / over 5 days) immediately clear to readers.
38
393. **Logic preserved**: The algorithm is identical — an O(n) single pass over `daysLate` with O(1) extra space.
40
41**Alternative perspective**: If you prefer a more functional style, the loop could be replaced with `std::accumulate`:
42
43```cpp
44int totalFee = accumulate(daysLate.begin(), daysLate.end(), 0,
45 [&](int sum, int days) { return sum + calculateFee(days); });
461/**
2 * Calculates the late fee for a single item based on the number of days it is late.
3 *
4 * Fee rules:
5 * - Exactly 1 day late: fee is 1.
6 * - More than 5 days late: fee is 3 per day.
7 * - Otherwise (2 to 5 days late): fee is 2 per day.
8 *
9 * @param days - The number of days an item is late.
10 * @returns The late fee for that item.
11 */
12const calculateFee = (days: number): number => {
13 if (days === 1) {
14 // Only 1 day late: flat fee of 1
15 return 1;
16 } else if (days > 5) {
17 // More than 5 days late: 3 per day
18 return 3 * days;
19 }
20 // Between 2 and 5 days late: 2 per day
21 return 2 * days;
22};
23
24/**
25 * Computes the total late fee for all items.
26 *
27 * @param daysLate - An array where each element represents the number of days an item is late.
28 * @returns The sum of late fees for all items.
29 */
30function lateFee(daysLate: number[]): number {
31 // Accumulate the fee of each item into a total sum
32 return daysLate.reduce((totalFee, days) => totalFee + calculateFee(days), 0);
33}
34Time and Space Complexity
-
Time Complexity:
O(n), wherenis the length of the arraydaysLate. The code iterates through each element of the array exactly once, and for each element, the helper functionf(x)performs only constant-time operations (comparisons and arithmetic). -
Space Complexity:
O(1). The solution uses a generator expression insidesum, which processes elements one at a time without creating an intermediate list, so only a constant amount of extra space is required.
Pattern Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall: Mishandling boundary values due to incorrect condition ordering or off-by-one comparisons
The fee rules form three tiers with two boundaries (x = 1 and x = 5), and it is surprisingly easy to break the logic at exactly those points. Two frequent mistakes:
1. Using the wrong comparison operator at the 5-day boundary
# WRONG: a book that is exactly 5 days late is charged 3 * 5 = 15
# instead of the correct 2 * 5 = 10
def calculate_fee(days: int) -> int:
if days == 1:
return 1
if days >= 5: # should be days > 5
return 3 * days
return 2 * days
The rule says "between 2 and 5 days late (inclusive)" pays 2 * days, so days == 5 must fall into the middle tier. Writing >= 5 silently overcharges every 5-day-late book, and simple test cases like [1, 3, 6] will still pass — the bug only surfaces when the input contains exactly 5.
2. Reordering chained conditions in the compact ternary version
# WRONG: the d <= 5 branch swallows d == 1, so a 1-day-late book
# is charged 2 * 1 = 2 instead of 1
return sum(2 * d if d <= 5 else 1 if d == 1 else 3 * d for d in daysLate)
In a chained conditional expression, conditions are evaluated left to right, and the first match wins. Because d == 1 also satisfies d <= 5, the more specific check must come first; otherwise the d == 1 branch becomes unreachable dead code.
Solution
- Order checks from most specific to most general: handle
days == 1first, thendays > 5, and let the final branch cover the remaining[2, 5]range. This way no explicit range check is needed and no branch can shadow another. - Use a strict comparison (
days > 5) for the top tier so thatdays == 5correctly falls into the2 * daystier. - Verify with boundary-focused test cases rather than only the sample input:
assert Solution().lateFee([1]) == 1 # boundary: exactly 1 day assert Solution().lateFee([2]) == 4 # boundary: start of middle tier assert Solution().lateFee([5]) == 10 # boundary: end of middle tier (NOT 15) assert Solution().lateFee([6]) == 18 # boundary: start of top tier assert Solution().lateFee([1, 3, 6]) == 25 # sample case
If your implementation passes all five assertions — especially the [5] case — the tier boundaries are handled correctly.
Ready to land your dream job?
Unlock your dream job with a 5-minute quiz for a personalized study roadmap!
Get My RoadmapWhich of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion If you prefer videos here's a video that explains recursion in a fun and easy way Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask him
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity describes how the time needed
Want a Structured Path to Master System Design Too? Don’t Miss This!