I got a question that's pretty common on the forum, a combination of a Bootstrap-style problem and DoorDash Pay. The interviewer didn't give me any starter code, just the description below.
He said to assume I'm a downstream service and the data comes from upstream. The answer I wrote turned out to be correct, it's just that the data was test cases, not data mocked from an upstream interface. A few days later I got rejected and I have no idea where I went wrong. Anyone have any pointers? The question and the code I was given at the time were roughly like this:
Dasher Naive Pay
Background: as a Dasher, your pay is calculated based on "active time." The system logs your actions on different orders as events.
Rules and definitions:
- Base rate: pay is calculated per minute, at a base rate of $0.3/min.
- Active order: an order is considered active from when you accept it (ACCEPT) until you complete the delivery (FULFILL).
- Multiplicity (stacked pay): in the Part 1 logic, pay stacks linearly. If you're handling multiple active orders at the same time, the pay for each minute = number of active orders x base rate. Example: if you have two active orders at the same time for 10 minutes, the pay for that stretch is 2 x 0.3 x 10 = 6.0.
Input: events, a list of events, each containing:
time: when it happened, in minutes.orderId: the order's unique identifier.action: the action taken - only ACCEPT (starts billing) and FULFILL (ends billing) matter.
Output: return the Dasher's total pay (a double), rounded to two decimal places.
Worked example (Part 1):
Input events:
- 06:15 | Order A | ACCEPT
- 06:18 | Order B | ACCEPT
- 06:36 | Order A | FULFILL
- 06:45 | Order B | FULFILL
Calculation:
- 06:15 - 06:18 (3 min): only order A active. Pay: 3 x 0.3 x 1 = 0.9
- 06:18 - 06:36 (18 min): orders A and B active at the same time (stacked pay). Pay: 18 x 0.3 x 2 = 10.8
- 06:36 - 06:45 (9 min): order A already done, only order B active. Pay: 9 x 0.3 x 1 = 2.7
Total pay: 0.9 + 10.8 + 2.7 = 14.4.
package com.example.demo;
import java.util.*;
public class DasherPaySolution {
enum Action { ACCEPT, ARRIVE, PICKUP, FULFILL }
static class Event {
int time;
String orderId;
Action action;
Event(int time, String orderId, Action action) {
this.time = time;
this.orderId = orderId;
this.action = action;
}
}
static class PeakWindow {
int start, end;
PeakWindow(int start, int end) {
this.start = start;
this.end = end;
}
}
private static final double BASE_RATE_PER_MIN = 0.3;
private static final Map<Action, Integer> ACTION_PRIORITY;
static {
Map<Action, Integer> map = new HashMap<>();
map.put(Action.ACCEPT, 0);
map.put(Action.ARRIVE, 1);
map.put(Action.PICKUP, 2);
map.put(Action.FULFILL, 3);
ACTION_PRIORITY = Collections.unmodifiableMap(map);
}
private static void sortEventsStable(List<Event> events) {
Collections.sort(events, new Comparator<Event>() {
@Override
public int compare(Event a, Event b) {
if (a.time != b.time) return a.time - b.time;
return ACTION_PRIORITY.get(a.action) - ACTION_PRIORITY.get(b.action);
}
});
}
// Part 1
public static double calculateNaivePay(List<Event> events) {
if (events == null || events.size() < 2) return 0.0;
sortEventsStable(events);
Set<String> activeOrders = new HashSet<>();
double pay = 0.0;
for (int i = 0; i < events.size() - 1; i++) {
Event cur = events.get(i);
if (cur.action == Action.ACCEPT) {
activeOrders.add(cur.orderId);
} else if (cur.action == Action.FULFILL) {
activeOrders.remove(cur.orderId);
}
int a = cur.time, b = events.get(i + 1).time;
double minutes = Math.max(0, b - a);
pay += minutes * BASE_RATE_PER_MIN * activeOrders.size();
}
return round2(pay);
}
int a = cur.time, b = events.get(i + 1).time;
double total = Math.max(0, b - a);
if (total == 0) continue;
int multiplicity = (atStoreOrder != null && activeOrders.contains(atStoreOrder))
? 1 : activeOrders.size();
double rate = BASE_RATE_PER_MIN * multiplicity;
double inPeak = 0.0;
while (p < merged.size() && merged.get(p).end <= a) p++;
int j = p;
while (j < merged.size() && merged.get(j).start < b) {
int s = Math.max(a, merged.get(j).start);
int t = Math.min(b, merged.get(j).end);
if (t > s) inPeak += (t - s);
if (merged.get(j).end <= b) j++; else break;
}
inPeak = Math.min(inPeak, total);
double nonPeak = total - inPeak;
pay += nonPeak * rate + inPeak * rate * 2.0;
}
private static List<PeakWindow> mergePeakWindows(List<PeakWindow> peaks) {
if (peaks == null || peaks.isEmpty()) return new ArrayList<>();
List<PeakWindow> list = new ArrayList<>(peaks);
Collections.sort(list, new Comparator<PeakWindow>() {
@Override
public int compare(PeakWindow a, PeakWindow b) {
return a.start - b.start;
}
});
List<PeakWindow> merged = new ArrayList<>();
PeakWindow cur = list.get(0);
for (int i = 1; i < list.size(); i++) {
PeakWindow nxt = list.get(i);
if (nxt.start <= cur.end) {
cur = new PeakWindow(cur.start, Math.max(cur.end, nxt.end));
} else {
merged.add(cur);
cur = nxt;
}
}
merged.add(cur);
return merged;
}
private static double round2(double x) {
return Math.round(x * 100.0) / 100.0;
}
public static int toMinutes(String hhmm) {
String[] t = hhmm.split(":");
return Integer.parseInt(t[0]) * 60 + Integer.parseInt(t[1]);
}
public static void main(String[] args) {
// --- Part 1 ---
List<Event> part1Events = Arrays.asList(
new Event(toMinutes("06:15"), "A", Action.ACCEPT),
new Event(toMinutes("06:18"), "B", Action.ACCEPT),
new Event(toMinutes("06:36"), "A", Action.FULFILL),
new Event(toMinutes("06:45"), "B", Action.FULFILL)
);
System.out.println("[Part 1] Expected: $14.4, Actual: $" + calculateNaivePay(new ArrayList<Event>(part1Events)));
}
}
Discussion
Loading comments…