Trip: 2008 FRQ 1
A step-by-step solution to the 2008 AP CSA FRQ 1 (Trip), covering ArrayList traversal, accumulating a total duration, and tracking a running minimum across a list of flights in Java.
A travel agency's list of connecting flights drives this AP Computer Science A free-response question — you total up how long an entire trip takes from start to finish, then hunt through it for the tightest connection between any two flights.
What This FRQ Tests
- AP CSA units: Unit 6 (Array) and Unit 7 (ArrayList)
- Core skill: traversing an
ArrayListof custom objects to accumulate and compare values pulled from a helper method - Secondary skill: recognizing when a special case (an empty list, or a list too short to have a layover) needs to be handled before the main loop logic even runs
- Official category: officially FRQ 1 by this exam's own printed numbering — but 2008 predates the fixed FRQ-number-to-category order introduced with the 2019–2020 CED redesign. Content-wise, this is actually an Array/ArrayList question (traversing an
ArrayList<Flight>), not a "Methods and Control Structures" one, despite sitting in the FRQ 1 slot.
The Setup
- A
Timeclass (not modified) provides one method:int minutesUntil(Time other)— the number of minutes from this time toother; negative ifotheris earlier
- A
Flightclass (not modified) provides:Time getDepartureTime()Time getArrivalTime()
- A
Tripclass holds:private ArrayList<Flight> flights— the flights of the trip, stored in chronological order
- You're asked to write two methods:
getDuration()— minutes from the first flight's departure to the last flight's arrivalgetShortestLayover()— the smallest gap between one flight's arrival and the next flight's departure
Part (a): Writing getDuration()
The Rule, Broken Down
- If there are no flights at all, the duration is
0. - Otherwise, the duration is the time from the first flight's departure to the last flight's arrival — not the sum of each individual flight's own flying time, and not something that needs the layovers added in separately, since they're already included between those two endpoints.
Step-by-Step Approach
- Check whether
flightsis empty; if so, return0immediately. - Otherwise, get the first flight (index
0) and the last flight (indexflights.size() - 1). - Call
minutesUntilon the first flight's departure time, passing in the last flight's arrival time. - Return that result.
The Code
public int getDuration()
{
if (flights.size() == 0)
{
return 0;
}
Flight first = flights.get(0);
Flight last = flights.get(flights.size() - 1);
return first.getDepartureTime().minutesUntil(last.getArrivalTime());
}
Why Each Piece Matters
- Checking
flights.size() == 0first — callingflights.get(0)on an empty list would throw an exception, so the empty case has to be handled before anything else runs. flights.size() - 1for the last flight — the trip can have any number of flights, so the last index always has to be computed, never hardcoded.- Calling
minutesUntilon the first flight's departure, not the last flight's arrival —minutesUntilreturns a value relative to this time, sofirst.getDepartureTime().minutesUntil(last.getArrivalTime())reads as "minutes from the first departure to the last arrival," which is exactly the duration being asked for. Calling it the other way around would return the same distance as a negative number.
Part (b): Writing getShortestLayover()
The Rule, Broken Down
- A layover is the number of minutes between one flight's arrival and the very next flight's departure.
- If there are fewer than two flights, there's no layover to measure at all — return
-1. - Otherwise, return the smallest layover found across every consecutive pair of flights.
Step-by-Step Approach
- Check whether
flights.size()is less than2; if so, return-1immediately. - Compute the layover between the first two flights and use it as the starting "shortest" value.
- Loop through the remaining consecutive pairs of flights.
- For each pair, compute that layover and compare it to the current shortest, replacing it if this one is smaller.
- After the loop, return the shortest layover found.
The Code
public int getShortestLayover()
{
if (flights.size() < 2)
{
return -1;
}
int shortest = flights.get(0).getArrivalTime().minutesUntil(flights.get(1).getDepartureTime());
for (int i = 1; i < flights.size() - 1; i++)
{
int layover = flights.get(i).getArrivalTime().minutesUntil(flights.get(i + 1).getDepartureTime());
if (layover < shortest)
{
shortest = layover;
}
}
return shortest;
}
Why Each Piece Matters
flights.get(i).getArrivalTime().minutesUntil(flights.get(i + 1).getDepartureTime())— this is "this flight's arrival" callingminutesUntilon "the next flight's departure," which is precisely how a layover is defined in the problem.- The loop only runs while
i < flights.size() - 1—i + 1is used inside the loop body, soican never be allowed to reach the last valid index, orflights.get(i + 1)would run off the end of the list. - Seeding
shortestwith the first pair's layover, instead of0or some arbitrary sentinel — since a real layover from this data is guaranteed to exist once there are at least two flights, starting from an actual computed value avoids having to guess what a "safe" starting number would be.
Tracing the Example
Using the question's own vacation example — four flights with these departure/arrival times:
| Flight | Departure | Arrival | Layover to next |
|---|---|---|---|
| 0 | 11:30 a.m. | 12:15 p.m. | 60 |
| 1 | 1:15 p.m. | 3:45 p.m. | 15 |
| 2 | 4:00 p.m. | 6:45 p.m. | 210 |
| 3 | 10:15 p.m. | 11:00 p.m. | — |
shorteststarts at the layover between Flight 0 and Flight 1:60.i = 1: layover between Flight 1 and Flight 2 is15, which is less than60, soshortestbecomes15.i = 2: layover between Flight 2 and Flight 3 is210, which is not less than15, soshorteststays15.- Final result: 15 — matches
vacation.getShortestLayover()exactly, as stated in the question.
The question doesn't give a directly stated expected value for getDuration() on this same data (only for getShortestLayover()), but the same table lets us check it ourselves: from Flight 0's departure (11:30 a.m.) to Flight 3's arrival (11:00 p.m.) is 690 minutes (11 hours, 30 minutes) — a number we computed by hand from the given times, not one stated by the official prompt.
Common Mistakes to Avoid
- Looping with the wrong bound, such as
i < flights.size(), which would letflights.get(i + 1)run past the end of the list on the final iteration. - Starting
shortestat0. A layover can never legitimately be0or negative here, but seeding with0would make theif (layover < shortest)check never true, so the method would incorrectly always return0. - Forgetting the fewer-than-two-flights case. Without it,
flights.get(1)would throw an exception on aTripwith zero or one flight. - Calling
minutesUntilon the wrong object (e.g.,flights.get(i + 1).getDepartureTime().minutesUntil(flights.get(i).getArrivalTime())), which would compute the layover as a negative number instead of positive.
Notes: A Method Not on the AP CSA Quick Reference Sheet
Math.min would let the comparison in part (b) collapse into a single line:
public int getShortestLayover()
{
if (flights.size() < 2)
{
return -1;
}
int shortest = flights.get(0).getArrivalTime().minutesUntil(flights.get(1).getDepartureTime());
for (int i = 1; i < flights.size() - 1; i++)
{
int layover = flights.get(i).getArrivalTime().minutesUntil(flights.get(i + 1).getDepartureTime());
shortest = Math.min(shortest, layover);
}
return shortest;
}
Math.minisn't listed on the real exam's Java Quick Reference sheet — onlyMath.abs,Math.pow,Math.sqrt, andMath.randomare. That doesn't mean it's off-limits; AP CSA graders accept any correct Java, whether or not it happens to appear on that sheet.- What the sheet actually guarantees is that those specific methods are printed for you to look up during the exam if you blank on the exact signature.
Math.minis completely safe to use if you're confident in it — theifversion above is simply the one that doesn't depend on remembering it.
Key Takeaways
- Special cases (an empty list, a list too short for the operation being asked) belong in a check at the very top of the method, before any indexing into the list happens.
- "Compare every consecutive pair" is a loop pattern where the loop bound has to leave room for looking one element ahead —
i < list.size() - 1, noti < list.size(). - Seeding a running "best so far" value with an actual computed value from the data (rather than a guessed sentinel like
0) sidesteps having to reason about whether that sentinel is actually safe.