Lesson 4.5: Algorithms with Arrays

Unit 4 · Lesson 4.5 · Arrays

Lesson 4.5: Algorithms with Arrays

🕑 45–55 min · 10 Practice Questions · Algorithm Patterns · FRQ Prep

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 to double before dividing for average.
  • Linear search (exists): Return true inside loop on match; return false after loop.
  • Linear search (index): Return the index inside loop on match; return -1 after 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

MCQ 1
Consider the following code:
int[] nums = {3, 7, 2, 9, 4};
findMax(nums);
What value is returned by findMax using the standard max algorithm?
Predict before reading the options.
A 7
B 3
C 9
D 4
C. The max algorithm initializes to arr[0]=3, then compares 7 (new max), 2 (no), 9 (new max), 4 (no). Returns 9.
MCQ 2
Which initialization is correct for a maximum algorithm on an array of integers that may include negative numbers?
A
int max = 0;
B
int max = arr[0];
C
int max = Integer.MAX_VALUE;
D
int max = arr.length;
B. Initializing to 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.
MCQ 3
What does this method return for input {4, 8, 2, 8, 1}?
public static int mystery(int[] arr) {
    int total = 0;
    for (int x : arr) {
        total += x;
    }
    return total / arr.length;
}
Watch the division carefully.
A 4.6
B 5
C 23
D 4
D. total = 4+8+2+8+1 = 23. 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.
MCQ 4
Consider the following code:
int[] arr = {5, 3, 8, 3, 2};
indexOf(arr, 3);
What value is returned?
Predict before reading the options.
A 1
B 3
C 2
D -1
A. Linear search returns the index of the first match. arr[0]=5 (no), arr[1]=3 (match!) → returns 1 immediately. Even though 3 also appears at index 3, the method exits on the first match. D (-1) would mean not found.
MCQ 5
Which placement of return false causes the linear search to incorrectly exit after checking only the first element?
A
for (int x : arr) {
    if (x == target) {
        return true;
    }
}
return false;
B
for (int x : arr) {
    if (x == target) {
        return true;
    }
}
return false; // after loop
C
for (int x : arr) {
    if (x == target) {
        return true;
    }
    return false; // inside loop
}
D
for (int x : arr) {
    if (x != target) {
        continue;
    }
    return true;
}
return false;
C. In C, 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.
Tier 3 · AP Mastery

Mastery: Algorithms with Arrays

MCQ 6
A Song class has a method getDuration() returning an int (seconds). Given Song[] playlist, which method correctly finds the shortest song duration?
Predict before reading the options.
A
int min = 0;
for (Song s : playlist) {
    if (s.getDuration() < min) {
        min = s.getDuration();
    }
}
return min;
B
int min = playlist[0].getDuration();
for (int i = 1; i < playlist.length; i++) {
    if (playlist[i].getDuration() < min) {
        min = playlist[i].getDuration();
    }
}
return min;
C
int min = playlist[0].getDuration();
for (int i = 0; i < playlist.length; i++) {
    if (playlist[i].getDuration() > min) {
        min = playlist[i].getDuration();
    }
}
return min;
D
int min = playlist.length;
for (Song s : playlist) {
    if (s.getDuration() < min) {
        min = s.getDuration();
    }
}
return min;
B. A initializes min to 0 — if all songs are longer than 0 seconds (they all are), min never updates and returns 0. C uses > — 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 <.
MCQ 7
Consider the following code:
int[] vals = {-3, 0, 5, -1, 2, 8};
countAbove(vals, 0);
What value is returned?
Predict before reading the options.
A 4
B 2
C 4
D 3
D. The condition is 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.
MCQ 8
Which code correctly computes the average of a double[] array named data?
Predict before reading the options.
A
double sum = 0;
for (double d : data) {
    sum += d;
}
return sum / data.length;
B
int sum = 0;
for (double d : data) {
    sum += d;
}
return sum / data.length;
C
double sum = 0;
for (double d : data) {
    sum += d;
}
return (int) sum / data.length;
D
double sum = 0;
for (int i = 1; i < data.length; i++) {
    sum += data[i];
}
return sum / data.length;
A. B uses an 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.
MCQ 9
A method should return the index of the last occurrence of a target value in an array, or -1 if not found. Which implementation is correct?
Think about what needs to change from the standard linear search.
A
for (int i = 0; i < arr.length; i++) {
    if (arr[i] == target) {
        return i;
    }
}
return -1;
B
for (int i = arr.length - 1; i >= 0; i--) {
    if (arr[i] == target) {
        return i;
    }
    return -1;
}
C
int lastIndex = -1;
for (int i = 0; i < arr.length; i++) {
    if (arr[i] == target) {
        lastIndex = i;
    }
}
return lastIndex;
D
for (int i = arr.length; i >= 0; i--) {
    if (arr[i] == target) {
        return i;
    }
}
return -1;
C. A returns the first occurrence (not last). B puts 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.
MCQ 10
A Student class has getName() and getGrade() (returns int 9–12). Given Student[] roster, which method correctly returns the number of 11th graders?
Predict before reading the options.
A
int count = 0;
for (Student s : roster) {
    if (s.getName() == 11) {
        count++;
    }
}
return count;
B
int count = 0;
for (Student s : roster) {
    if (s.getGrade() == 11) {
        count++;
    }
}
return count;
C
int count = 0;
for (Student s : roster) {
    if (s.getGrade() > 11) {
        count++;
    }
}
return count;
D
int count = 0;
for (Student s : roster) {
    if (s.getGrade() == 11) {
        return count;
    }
}
return count;
B. A calls 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.

Typically responds within 24 hours

Message Sent!

Thanks for reaching out. I'll get back to you within 24 hours.

🏫 Welcome, fellow educator!

I offer curriculum resources, practice materials, and study guides designed for AP CS teachers. Let me know what you're looking for — whether it's classroom materials, a guest speaker, or Teachers Pay Teachers resources.

Email

[email protected]

📚

Courses

AP CSA, CSP, & Cybersecurity

Response Time

Within 24 hours

Prefer email? Reach me directly at [email protected]