Lesson 4.5: Algorithms with Arrays
Lesson 4.5: Algorithms with Arrays
What You'll Learn
- 4.5.A: Apply standard algorithms to arrays.
- Implement minimum, maximum, sum, and average algorithms.
- Implement linear search — both existence check and index-finding versions.
- Implement a frequency count and identify all occurrences of a value.
- Recognize these patterns in AP exam MCQ and reproduce them in FRQ responses.
📌 Why This Lesson Matters
The AP exam tests a small set of standard array algorithms over and over — in MCQ output tracing, in "which code is correct" questions, and directly in FRQ #3. Every pattern in this lesson has appeared on at least one AP exam in the last five years. Learn the template, not just the example.
Algorithm Patterns at a Glance
| Algorithm | What It Computes |
|---|---|
| Minimum / Maximum | The smallest or largest value in the array |
| Sum / Average | Total of all values; total divided by count |
| Linear Search (exists) | Whether a target value appears in the array |
| Linear Search (index) | The index of a target value, or -1 if not found |
| Frequency Count | How many elements meet a given condition |
Minimum and Maximum
The key insight: initialize your running min/max to the first element, then loop from index 1 onward comparing each element.
// Maximum
public static int findMax(int[] arr) {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
// Minimum — identical structure, just flip the comparison
public static int findMin(int[] arr) {
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
return min;
}
⚠️ AP Exam Trap: Initializing to 0
Initializing max = 0 fails if all values are negative. Initializing min = 0 fails if all values are positive. Always initialize to arr[0] — the first element is guaranteed to be a valid value from the array.
Sum and Average
public static double average(int[] arr) {
int total = 0;
for (int x : arr) {
total += x;
}
return (double) total / arr.length;
}
⚠️ AP Exam Trap: Integer Division
If both total and arr.length are int, dividing them performs integer division and truncates the result. Cast one operand to double first: (double) total / arr.length. Placing the cast after the division — (double)(total / arr.length) — is too late and still truncates.
Linear Search
Linear search scans every element from left to right until it finds the target. There are two versions depending on what you need to return.
Version 1: Does the target exist? (returns boolean)
public static boolean contains(int[] arr, int target) {
for (int x : arr) {
if (x == target) {
return true;
}
}
return false;
}
The return true is inside the loop — it exits the moment the target is found. The return false is outside — it only runs if the entire array was searched without a match.
Version 2: Where is the target? (returns index)
public static int indexOf(int[] arr, int target) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
return -1;
}
Returns the index if found, -1 if not. The convention of returning -1 for "not found" is standard Java practice — String.indexOf() uses the same pattern.
📌 Why -1 and Not 0?
Returning 0 would be ambiguous — 0 is a valid index. Returning -1 is an unambiguous signal that the target wasn't found, since -1 is never a valid array index.
⚠️ AP Exam Trap: Early Return Placement
The return false / return -1 must be outside the loop. Placing it inside causes the method to return after checking only the first element — the search never continues past index 0.
Frequency Count
Count how many elements satisfy a condition:
// Count elements greater than a threshold
public static int countAbove(int[] arr, int threshold) {
int count = 0;
for (int x : arr) {
if (x > threshold) {
count++;
}
}
return count;
}
The counter starts at 0 and increments every time the condition is true. This pattern handles any condition — equal to a value, greater than, even/odd, negative, etc.
Applying These Algorithms to Object Arrays
All five patterns work identically on arrays of objects — just call the appropriate getter instead of reading a primitive directly:
// Find student with highest score
public static int highestScore(Student[] roster) {
int max = roster[0].getScore();
for (int i = 1; i < roster.length; i++) {
if (roster[i].getScore() > max) {
max = roster[i].getScore();
}
}
return max;
}
// Count students who passed (score >= 70)
public static int countPassing(Student[] roster) {
int count = 0;
for (Student s : roster) {
if (s.getScore() >= 70) {
count++;
}
}
return count;
}
📌 FRQ #3 Connection
Every AP CSA FRQ #3 gives you a class representing one record and asks you to write methods over a collection. The methods are always some combination of the five patterns above. Mastering these five patterns over object arrays puts you in a strong position for FRQ #3 — the questions change every year, but the underlying algorithm structure stays the same.
Summary
-
Min/Max: Initialize to
arr[0], loop from index 1, update when a better value is found. -
Sum/Average: Accumulate with
total += x; cast todoublebefore dividing for average. -
Linear search (exists): Return
trueinside loop on match; returnfalseafter loop. -
Linear search (index): Return the index inside loop on match; return
-1after loop. -
Frequency count: Initialize
count = 0, increment inside loop when condition is true. - All patterns apply to object arrays by calling getter methods instead of reading primitives.
Practice Questions
int[] nums = {3, 7, 2, 9, 4};
findMax(nums);
What value is returned by findMax using the standard max algorithm?int max = 0;
int max = arr[0];
int max = Integer.MAX_VALUE;
int max = arr.length;
arr[0] always works because it's a real value from the array. A fails if all values are negative. C initializes to the largest possible int — the max would never update. D uses the size, which has nothing to do with the values.{4, 8, 2, 8, 1}?
public static int mystery(int[] arr) {
int total = 0;
for (int x : arr) {
total += x;
}
return total / arr.length;
}
arr.length = 5. Both are ints, so 23 / 5 = 4 (integer division truncates the decimal). The true average is 4.6, but without a cast to double the decimal is lost. This is the integer division trap.int[] arr = {5, 3, 8, 3, 2};
indexOf(arr, 3);
What value is returned?return false causes the linear search to incorrectly exit after checking only the first element?for (int x : arr) {
if (x == target) {
return true;
}
}
return false;
for (int x : arr) {
if (x == target) {
return true;
}
}
return false; // after loop
for (int x : arr) {
if (x == target) {
return true;
}
return false; // inside loop
}
for (int x : arr) {
if (x != target) {
continue;
}
return true;
}
return false;
return false is inside the loop body but outside the if. After checking the first element: if it matches, returns true; if it doesn't, hits return false immediately — never checks the rest. A and B are identical and both correct. D uses continue but is also correct.Mastery: Algorithms with Arrays
Song class has a method getDuration() returning an int (seconds). Given Song[] playlist, which method correctly finds the shortest song duration?int min = 0;
for (Song s : playlist) {
if (s.getDuration() < min) {
min = s.getDuration();
}
}
return min;
int min = playlist[0].getDuration();
for (int i = 1; i < playlist.length; i++) {
if (playlist[i].getDuration() < min) {
min = playlist[i].getDuration();
}
}
return min;
int min = playlist[0].getDuration();
for (int i = 0; i < playlist.length; i++) {
if (playlist[i].getDuration() > min) {
min = playlist[i].getDuration();
}
}
return min;
int min = playlist.length;
for (Song s : playlist) {
if (s.getDuration() < min) {
min = s.getDuration();
}
}
return min;
> — finds maximum, not minimum. D initializes to playlist.length (count of songs) which is unrelated to duration values. B correctly initializes to the first element's duration and uses <.int[] vals = {-3, 0, 5, -1, 2, 8};
countAbove(vals, 0);
What value is returned?x > 0 (strictly greater than). Values: -3 ✗, 0 ✗ (0 is not greater than 0), 5 ✓, -1 ✗, 2 ✓, 8 ✓. Count = 3. Students often include 0 — the condition is strict greater-than, not greater-than-or-equal.double[] array named data?double sum = 0;
for (double d : data) {
sum += d;
}
return sum / data.length;
int sum = 0;
for (double d : data) {
sum += d;
}
return sum / data.length;
double sum = 0;
for (double d : data) {
sum += d;
}
return (int) sum / data.length;
double sum = 0;
for (int i = 1; i < data.length; i++) {
sum += data[i];
}
return sum / data.length;
int accumulator — doubles get truncated as they accumulate. C casts sum to int before dividing, losing the decimal. D starts at index 1 — skips data[0]. A correctly uses a double accumulator and divides without truncation.for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
return -1;
for (int i = arr.length - 1; i >= 0; i--) {
if (arr[i] == target) {
return i;
}
return -1;
}
int lastIndex = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
lastIndex = i;
}
}
return lastIndex;
for (int i = arr.length; i >= 0; i--) {
if (arr[i] == target) {
return i;
}
}
return -1;
return -1 inside the loop — exits after one element. D starts at arr.length which is out of bounds. C scans the full array, keeps updating lastIndex every time the target is found, and returns the final recorded index — the last occurrence.Student class has getName() and getGrade() (returns int 9–12). Given Student[] roster, which method correctly returns the number of 11th graders?int count = 0;
for (Student s : roster) {
if (s.getName() == 11) {
count++;
}
}
return count;
int count = 0;
for (Student s : roster) {
if (s.getGrade() == 11) {
count++;
}
}
return count;
int count = 0;
for (Student s : roster) {
if (s.getGrade() > 11) {
count++;
}
}
return count;
int count = 0;
for (Student s : roster) {
if (s.getGrade() == 11) {
return count;
}
}
return count;
getName() (returns a String) and compares it to an int — wrong getter, won't compile. C uses > 11 — counts 12th graders only. D returns count the moment the first 11th grader is found — never finishes counting. B correctly uses getGrade() == 11 and increments through the entire array.Get in Touch
Whether you're a student, parent, or teacher — I'd love to hear from you.
Just want free AP CS resources?
Enter your email below and check the subscribe box — no message needed. Students get daily practice questions and study tips. Teachers get curriculum resources and teaching strategies.
Message Sent!
Thanks for reaching out. I'll get back to you within 24 hours.
Prefer email? Reach me directly at [email protected]