LeetCode 3687 - Library Late Fee Calculator
The problem asks us to calculate the total late fee for a library based on how many days each book was returned late. You are given an integer array daysLate, where each element daysLate[i] represents the number of days the i-th book was returned past its due date.
Difficulty: 🟢 Easy
Topics: Array, Simulation
Solution
Problem Understanding
The problem asks us to calculate the total late fee for a library based on how many days each book was returned late. You are given an integer array daysLate, where each element daysLate[i] represents the number of days the i-th book was returned past its due date. The penalty rules are tiered: if a book is late by exactly 1 day, the penalty is 1; if it is late between 2 and 5 days inclusive, the penalty is twice the number of late days; and if it is late by more than 5 days, the penalty is three times the number of late days.
The input array can have between 1 and 100 elements, and each daysLate[i] is guaranteed to be between 1 and 100. This ensures we are working with a small-scale dataset, so performance is not a major concern, but we still want a clean and correct solution. Edge cases to consider include a single book being late, all books being late by 1 day, or all books being late by more than 5 days.
The expected output is a single integer, the sum of penalties for all books.
Approaches
The brute-force approach is straightforward: iterate over each book in daysLate, compute the penalty according to the given rules, and add it to a running total. This is simple, correct, and runs efficiently given the constraints, but it involves a repeated conditional check for each element.
The optimal approach leverages the same iteration but emphasizes clear tier-based calculation without unnecessary overhead. The insight here is that the problem is already simple and bounded, so the "optimization" mainly comes from clean, readable code rather than reducing complexity.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n) | O(1) | Iterate over the array and sum penalties using conditionals |
| Optimal | O(n) | O(1) | Same as brute force, but structured cleanly and clearly; no extra data structures |
Algorithm Walkthrough
- Initialize a variable
totalPenaltyto zero. This will store the running sum of penalties. - Loop over each element
daysin thedaysLatearray. - For each
days, determine the penalty using the given rules:
- If
daysis exactly 1, add 1 tototalPenalty. - If
daysis between 2 and 5 inclusive, add2 * daystototalPenalty. - If
daysis greater than 5, add3 * daystototalPenalty.
- After the loop completes, return
totalPenalty.
Why it works: The algorithm maintains a running sum of penalties and applies the exact rules for each book. Since each element is processed independently and correctly, the total sum at the end reflects the sum of all penalties.
Python Solution
from typing import List
class Solution:
def lateFee(self, daysLate: List[int]) -> int:
totalPenalty = 0
for days in daysLate:
if days == 1:
totalPenalty += 1
elif 2 <= days <= 5:
totalPenalty += 2 * days
else:
totalPenalty += 3 * days
return totalPenalty
In this implementation, totalPenalty accumulates the penalty for each book. The conditional structure clearly reflects the problem rules. Each iteration examines a single element, determines the appropriate penalty tier, and adds it to the running total.
Go Solution
func lateFee(daysLate []int) int {
totalPenalty := 0
for _, days := range daysLate {
if days == 1 {
totalPenalty += 1
} else if days >= 2 && days <= 5 {
totalPenalty += 2 * days
} else {
totalPenalty += 3 * days
}
}
return totalPenalty
}
In Go, the approach is identical. The range loop iterates over each element in the slice, and the conditional checks determine the correct penalty tier. Go uses := for initialization, and integer arithmetic is straightforward since all values are small and within the 32-bit integer range.
Worked Examples
Example 1: daysLate = [5, 1, 7]
| Iteration | days | Penalty | totalPenalty |
|---|---|---|---|
| 1 | 5 | 2 * 5 = 10 | 10 |
| 2 | 1 | 1 | 11 |
| 3 | 7 | 3 * 7 = 21 | 32 |
Final result: 32
Example 2: daysLate = [1, 1]
| Iteration | days | Penalty | totalPenalty |
|---|---|---|---|
| 1 | 1 | 1 | 1 |
| 2 | 1 | 1 | 2 |
Final result: 2
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each element in the array is visited exactly once |
| Space | O(1) | Only a single integer variable totalPenalty is used regardless of input size |
The algorithm is efficient and uses minimal memory. Since n <= 100, performance is not a concern.
Test Cases
# Provided examples
assert Solution().lateFee([5, 1, 7]) == 32 # mixed penalties
assert Solution().lateFee([1, 1]) == 2 # all minimal penalties
# Edge cases
assert Solution().lateFee([1]) == 1 # single book, minimum late
assert Solution().lateFee([100]) == 300 # single book, large late
assert Solution().lateFee([2, 3, 4, 5]) == 28 # all mid-range penalties
assert Solution().lateFee([6, 7, 8]) == 63 # all high penalties
assert Solution().lateFee([1, 2, 5, 6, 100]) == 1 + 4 + 10 + 18 + 300 # mixed extremes
| Test | Why |
|---|---|
[5,1,7] |
Validates all penalty tiers together |
[1,1] |
All minimum late penalties |
[1] |
Single-element edge case |
[100] |
Large late days single book |
[2,3,4,5] |
Mid-tier penalties only |
[6,7,8] |
High-tier penalties only |
[1,2,5,6,100] |
Mixed extremes to ensure summing works |
Edge Cases
One edge case is when the array contains a single element. This tests that the function correctly handles arrays of length one and does not assume multiple elements. Another edge case is when all elements are at the boundary values for penalty tiers, such as 1, 2, 5, and 6. This ensures that the conditional logic correctly handles inequalities. A third edge case is when all books are returned very late, for instance 100 days. This tests integer arithmetic and summing, ensuring no overflow or logic errors. In all cases, our implementation directly applies the rules per element, so it handles these edge cases correctly.