Trail: 2010 FRQ 3
A step-by-step solution to the 2010 AP CSA FRQ 3 (Trail), covering tracking a running maximum and minimum across an array segment and counting significant changes between consecutive elements in Java.
Reading elevation data out of a plain array of ints drives this AP Computer Science A free-response question, which asks for two unrelated methods on the same class — one that checks how "flat" a stretch of a hiking trail is, and another that counts how many times the trail suddenly rises or drops.
What This FRQ Tests
- AP CSA units: Unit 6 (Array) and Unit 4 (Iteration)
- Core skill: tracking a running maximum and minimum while scanning a subrange of an array
- Secondary skill: comparing each array element to its neighbor to detect and count meaningful changes
- Official category: "Array/ArrayList" — this coincidentally lands in the same slot a modern exam would use for array-based work, but 2010 predates the standardized FRQ-number-to-category order that AP CSA formalized starting with the 2019–2020 CED redesign, so that alignment isn't guaranteed for every older year. It's printed as FRQ 3 in the original exam.
The Setup
- The given
Trailclass has:private int[] markers— the elevation at each marker; the first marker is index0, andmarkers.lengthis the total number of markers
- You're asked to write two unrelated methods:
isLevelTrailSegment(int start, int end)— precondition0 <= start < end <= markers.length - 1; returnstrueif the difference between the highest and lowest elevation in that segment is<= 10metersisDifficult()— counts how many consecutive-marker elevation changes are>= 30meters in magnitude (up or down); returnstrueif there are 3 or more
Part (a): Writing isLevelTrailSegment(int start, int end)
The Rule, Broken Down
- A "trail segment" spans every marker from
starttoend, inclusive of both endpoints. - Find the highest and lowest elevation anywhere in that range.
- The segment is level if
highest - lowestis10or less — note this is inclusive, so a difference of exactly10still counts as level.
Step-by-Step Approach
- Initialize both a running
maxandmintomarkers[start]— the first marker in the segment is a safe starting point for both. - Loop from
start + 1throughend, inclusive. - On each iteration, update
maxif this marker's elevation is higher, and updateminif it's lower. - After the loop, return whether
max - minis<= 10.
The Code
public boolean isLevelTrailSegment(int start, int end)
{
int max = markers[start];
int min = markers[start];
for (int i = start + 1; i <= end; i++)
{
if (markers[i] > max)
{
max = markers[i];
}
if (markers[i] < min)
{
min = markers[i];
}
}
return max - min <= 10;
}
Why Each Piece Matters
- Initializing
maxandmintomarkers[start], not to0or some arbitrary sentinel value — elevations aren't guaranteed to be positive or fall in any particular range, so starting from an actual data point already inside the segment is always safe. - The loop starts at
start + 1, notstart— the marker atstartis already accounted for by the initialization, so re-checking it would just be redundant. i <= end, noti < end— the segment includes theendmarker itself, and the precondition guaranteesendis always a valid index, so there's no out-of-bounds risk.- Two separate
ifstatements, notif/else if— checking for a new max and a new min are independent questions; a single marker's elevation needs to be compared against bothmaxandminevery iteration.
Part (b): Writing isDifficult()
The Rule, Broken Down
- Compare every pair of consecutive markers:
markers[i]andmarkers[i + 1]. - Compute the elevation change between them — it can be positive (uphill) or negative (downhill).
- A change counts as "significant" if its magnitude is
30meters or more, regardless of direction. - If there are
3or more significant changes anywhere on the trail, it's rated difficult.
Step-by-Step Approach
- Start a counter at
0. - Loop
ifrom0up to (but not including)markers.length - 1— this keepsi + 1a valid index on every iteration. - On each iteration, compute
markers[i + 1] - markers[i]. - Take the absolute value of that change and compare it to
30; if it's at least30, increment the counter. - After the loop, return whether the counter is
3or more.
The Code
public boolean isDifficult()
{
int count = 0;
for (int i = 0; i < markers.length - 1; i++)
{
int change = markers[i + 1] - markers[i];
if (Math.abs(change) >= 30)
{
count++;
}
}
return count >= 3;
}
Why Each Piece Matters
markers.length - 1as the loop bound — since the loop body always looks ahead tomarkers[i + 1], lettingireachmarkers.length - 1itself would pushi + 1one index past the end of the array.Math.abs(change)— a "change" can be a downhill drop (a negative number), and the rule cares about the size of the change, not its direction.Math.absis listed on the AP Quick Reference sheet, so it's the natural default here rather than writing a manualifto flip the sign.- Comparing against
30with>=, not>— a change of exactly30meters still counts, per the rule's own wording ("at least 30 meters"). count >= 3, notcount == 3— "3 or more" means any count of3or higher should be rated difficult, not exactly3.
Tracing the Example
Using the trail data from the question — elevations 100, 150, 105, 120, 90, 80, 50, 75, 75, 70, 80, 90, 100 at indices 0–12:
| Markers | Change | Math.abs(change) |
>= 30? |
|---|---|---|---|
| 0 → 1 | 150 − 100 = 50 | 50 | yes |
| 1 → 2 | 105 − 150 = −45 | 45 | yes |
| 2 → 3 | 120 − 105 = 15 | 15 | no |
| 3 → 4 | 90 − 120 = −30 | 30 | yes |
| 4 → 5 | 80 − 90 = −10 | 10 | no |
| 5 → 6 | 50 − 80 = −30 | 30 | yes |
| 6 → 7 | 75 − 50 = 25 | 25 | no |
| 7 → 8 | 75 − 75 = 0 | 0 | no |
| 8 → 9 | 70 − 75 = −5 | 5 | no |
| 9 → 10 | 80 − 70 = 10 | 10 | no |
| 10 → 11 | 90 − 80 = 10 | 10 | no |
| 11 → 12 | 100 − 90 = 10 | 10 | no |
That's 4 significant changes (between markers 0–1, 1–2, 3–4, and 5–6) — exactly matching the question's own count and its list of which marker pairs triggered it. Since 4 >= 3, isDifficult() returns true, and this trail is rated difficult, also matching the question.
Common Mistakes to Avoid
- Comparing
change >= 30withoutMath.abs. This misses every downhill drop entirely — the-45and-30changes above would never be counted, undercounting the true number of significant changes. - Looping to
markers.lengthinstead ofmarkers.length - 1. This throws anArrayIndexOutOfBoundsExceptionon the final iteration, whenmarkers[i + 1]reaches past the last valid index. - Using
> 30instead of>= 30. Two of the four significant changes in the example above are exactly30in magnitude and must still be counted. - Returning
count == 3instead ofcount >= 3. A trail with4,5, or more significant changes is still difficult, not just one with exactly3.
Notes: Tracking Max/Min With Math.max/Math.min
Part (a)'s running max/min can be written more compactly using two more Math methods:
public boolean isLevelTrailSegment(int start, int end)
{
int max = markers[start];
int min = markers[start];
for (int i = start + 1; i <= end; i++)
{
max = Math.max(max, markers[i]);
min = Math.min(min, markers[i]);
}
return max - min <= 10;
}
Math.maxandMath.minaren't listed on the AP Quick Reference sheet — onlyMath.abs,Math.pow,Math.sqrt, andMath.randomare. That doesn't make them off-limits; AP CSA graders accept any correct Java. The tradeoff is simply that you won't have their exact signatures printed for you to double-check mid-exam, the way you would with theif-based version above.- Each line replaces a two-line
ifblock with a single reassignment, which is a common shorthand worth recognizing even if you choose to write the longer version on the actual exam.
Key Takeaways
- Tracking a running maximum and minimum over part of an array is a two-variable pattern: initialize both from the first element in range, then update each independently as you scan the rest.
- When checking whether a numeric change is "significant" in either direction, take its absolute value before comparing it to a threshold — comparing the raw signed value only ever catches increases.
- A loop that looks ahead to
i + 1(or back toi - 1) needs an adjusted bound (length - 1, notlength) so the lookahead index never steps outside the array.