Trip expense binder
MediumOnline Assessment
File a pile of expense items into trip reports. Trips can overlap, and receipts often turn up a day or two outside the trip.
Each trip is a string "name START END", with dates YYYY-MM-DD; the trip covers every day from START to END inclusive (START <= END). Each item is a string "DATE CENTS": the date of the expense and its amount in cents, an integer that is negative for a refund. Trip names are unique.
Each item is filed under at most one trip:
- If its date lies inside one or more trips, it goes to the one that started latest; if several of those started on the same day, to the one listed first in
trips. - Otherwise, it is a *near miss* for a trip if it is within
slackdays of it: the item is beforeSTARTby at mostslackdays, or afterENDby at mostslackdays (slackmay be 0). Among the trips it is a near miss for, it goes to the one with the smallest gap in days (a day beforeSTARTor afterENDis a gap of 1); if the gaps tie, to the one listed first. - Otherwise, it is unassigned.
Dates are real calendar dates, so months, leap years and year ends behave normally.
Input: trips, a list of strings; items, a list of strings; slack, a non-negative integer.
Output: a list of strings "name COUNT TOTAL", one for each trip with at least one item, where COUNT is the number of items filed and TOTAL their sum in cents (it can be zero or negative). Order the trips by START ascending, then by name ascending. If at least one item is unassigned, add a final line "unassigned COUNT TOTAL" in the same format (no trip is called unassigned). If there are no items, return [].
Example 1
- Input:
- [["berlin 2024-03-04 2024-03-08","paris 2024-03-07 2024-03-12","austin 2024-04-01 2024-04-03"],["2024-03-04 1200","2024-03-07 3500","2024-03-08 900","2024-03-12 2000","2024-03-13 700","2024-03-15 5000","2024-03-02 800","2024-03-30 150","2024-04-02 -300"],2]
- Output:
- ["berlin 2 2000","paris 4 7100","austin 2 -150","unassigned 1 5000"]
- Explanation
- March 7 and 8 are inside both
berlin(3/4-3/8) andparis(3/7-3/12);parisstarted later, so it gets both. March 13 is one day afterparisends (within slack 2) and March 2 is two days beforeberlinstarts, so those are near misses that attach. March 15 is three days pastparis, too far, so it is unassigned. March 30 is two days beforeaustin, and the refund on April 2 is inside it:austintotals 150 - 300 = -150. Trips are ordered by start date.
Example 2
- Input:
- [["conf 2024-05-10 2024-05-12","retreat 2024-05-16 2024-05-18"],["2024-05-14 100","2024-05-13 50","2024-05-15 70","2024-05-20 30","2024-05-06 10"],3]
- Output:
- ["conf 2 150","retreat 2 100","unassigned 1 10"]
- Explanation
- May 14 is a near miss for both trips with a gap of 2 (two days after
conf, two days beforeretreat); the tie goes to the trip listed first,conf. May 13 is 1 day afterconfand May 15 is 1 day beforeretreat. May 20 is two days afterretreatends. May 6 is four days beforeconf, more than the slack of 3, so it is unassigned.
Example 3
- Input:
- [["b 2024-12-30 2025-01-02","a 2024-12-30 2025-01-05","c 2025-01-03 2025-01-03"],["2024-12-31 100","2025-01-03 10","2025-01-04 -5","2025-01-06 7","2024-12-29 1"],0]
- Output:
- ["a 1 -5","b 1 100","c 1 10","unassigned 2 8"]
- Explanation
- With slack 0 only dates inside a trip count. December 31 is inside both
banda, which started on the same day, so the first listed,b, gets it. January 3 is insideaandc;cstarted later. January 4 only ina. January 6 and December 29 are outside everything. Output is ordered by start date, and the tie betweenaandbis broken by name even thoughbis listed first.
Constraints
0 <= trips.length <= 50and0 <= items.length <= 1,000- Dates are valid calendar dates between 2000-01-01 and 2099-12-31;
0 <= slack <= 30 - Trip names are 1 to 10 ASCII letters or digits and distinct; amounts are integers with absolute value at most 107