FRQ Corrections
2014a. FRQ
public class WordScrambler {
private String[] scrambledWords;
/**
* Constructor initializes scrambledWords with mixed words from the given array.
* @param wordArr an array of String objects (even length assumed)
*/
public WordScrambler(String[] wordArr) {
scrambledWords = mixedWords(wordArr);
}
/**
* Takes two words and combines them by taking the first half of the first word
* and the second half of the second word.
* @param word1 The first word
* @param word2 The second word
* @return A new string formed by taking the first half of word1 and the second half of word2
*/
private String recombine(String word1, String word2) {
// Find the halfway point of each word
int mid1 = word1.length() / 2;
int mid2 = word2.length() / 2;
// Concatenate the first half of word1 with the second half of word2
return word1.substring(0, mid1) + word2.substring(mid2);
}
/**
* Takes an array of words and forms a new array where each pair of words is recombined.
* @param words An array of String objects (assumed to be of even length)
* @return A new array with the same length where every pair of words is recombined
*/
private String[] mixedWords(String[] words) {
// Create a new array to store the recombined words
String[] mixed = new String[words.length];
// Process words in pairs
for (int i = 0; i < words.length; i += 2) {
// Apply recombine function to the pair of words
mixed[i] = recombine(words[i], words[i + 1]);
mixed[i + 1] = recombine(words[i + 1], words[i]); // Swap order for second recombination
}
return mixed;
}
}
2014b. FRQ
public class Mountain {
/**
* @param array an array of positive integer values
* Precondition: array.length > 0
* @return the index of the first peak (local maximum) in the array, if it exists;
* -1 otherwise
*/
public static int getPeakIndex(int[] array) {
for (int i = 1; i < array.length - 1; i++) {
if (array[i] > array[i - 1] && array[i] > array[i + 1]) {
return i; // Found the first peak
}
}
return -1; // No peak found
}
/**
* @param array an array of positive integer values
* Precondition: array.length > 0
* @return true if array contains values ordered as a mountain;
* false otherwise
*/
public static boolean isMountain(int[] array) {
int peakIndex = getPeakIndex(array);
// A valid mountain must have a peak that is not at the beginning or the end
if (peakIndex <= 0 || peakIndex >= array.length - 1) {
return false;
}
// Check increasing sequence before peak
for (int i = 0; i < peakIndex; i++) {
if (array[i] >= array[i + 1]) {
return false; // Must be strictly increasing
}
}
// Check decreasing sequence after peak
for (int i = peakIndex; i < array.length - 1; i++) {
if (array[i] <= array[i + 1]) {
return false; // Must be strictly decreasing
}
}
return true; // It follows mountain property
}
// Main method for testing
public static void main(String[] args) {
int[][] testCases = {
{1, 2, 3, 2, 1},
{1, 2, 2, 1},
{1, 2, 3, 4},
{99, 33, 55, 77, 55},
{3, 2, 1},
{1, 2, 3, 2, 2}
};
for (int[] testCase : testCases) {
System.out.println("Array: " + java.util.Arrays.toString(testCase));
System.out.println("Peak Index: " + getPeakIndex(testCase));
System.out.println("Is Mountain: " + isMountain(testCase));
System.out.println();
}
}
}
2014c. FRQ
public class TemperatureGrid {
// A two-dimensional array of temperature values, initialized in the constructor (not shown)
// Guaranteed not to be null
private double[][] temps;
/**
* Computes and returns a new temperature value for the given location.
* @param row a valid row index in temps
* @param col a valid column index in temps
* @return the new temperature for temps[row][col]
* - The new temperature for any element in the border of the array is the same as the old temperature.
* - Otherwise, the new temperature is the average of the four adjacent entries.
* Postcondition: temps is unchanged.
*/
private double computeTemp(int row, int col) {
int numRows = temps.length;
int numCols = temps[0].length;
// If the element is on the border, return the same value
if (row == 0 || row == numRows - 1 || col == 0 || col == numCols - 1) {
return temps[row][col];
}
// Compute the average of the four adjacent elements
return (temps[row - 1][col] + temps[row + 1][col] + temps[row][col - 1] + temps[row][col + 1]) / 4.0;
}
/**
* Updates all values in temps and returns a boolean that indicates whether or not all the
* new values were within tolerance of the original values.
* @param tolerance a double value >= 0
* @return true if all updated temperatures are within tolerance of the original values;
* false otherwise.
* Postcondition: Each value in temps has been updated with a new value based on the
* corresponding call to computeTemp.
*/
public boolean updateAllTemps(double tolerance) {
int numRows = temps.length;
int numCols = temps[0].length;
boolean withinTolerance = true;
// Create a new array to store updated temperatures
double[][] newTemps = new double[numRows][numCols];
// Compute new temperatures
for (int row = 0; row < numRows; row++) {
for (int col = 0; col < numCols; col++) {
newTemps[row][col] = computeTemp(row, col);
// Check if the difference is within tolerance
if (Math.abs(newTemps[row][col] - temps[row][col]) > tolerance) {
withinTolerance = false;
}
}
}
// Update temps with the new computed values
for (int row = 0; row < numRows; row++) {
for (int col = 0; col < numCols; col++) {
temps[row][col] = newTemps[row][col];
}
}
return withinTolerance;
}
}
2014d. FRQ
import java.util.*;
public class Stats {
private ArrayList<ScoreInfo> scoreList; // Maintained in increasing score order
/**
* Records a score in the database, keeping the database in increasing score order.
* If no other ScoreInfo object represents score, a new ScoreInfo object representing
* score is added to the database; otherwise, the frequency in the ScoreInfo object
* representing score is incremented.
*
* @param score a score to be recorded in the list
* @return true if a new ScoreInfo object representing score was added to the list;
* false otherwise
*/
public boolean record(int score) {
// Iterate through the list to find the correct position
for (int i = 0; i < scoreList.size(); i++) {
ScoreInfo info = scoreList.get(i);
if (info.getScore() == score) {
// Score already exists, increment frequency
info.increment();
return false;
} else if (info.getScore() > score) {
// Insert new ScoreInfo at the correct position
scoreList.add(i, new ScoreInfo(score));
return true;
}
}
// If score is larger than all existing scores, add it at the end
scoreList.add(new ScoreInfo(score));
return true;
}
/**
* Records all scores in stuScores in the database, keeping the database in increasing score order.
*
* @param stuScores an array of student test scores
*/
public void recordScores(int[] stuScores) {
for (int score : stuScores) {
record(score);
}
}
// Constructor (not shown in prompt but necessary for testing)
public Stats() {
scoreList = new ArrayList<>();
}
// Method for testing
public void printScores() {
for (ScoreInfo info : scoreList) {
System.out.println("Score: " + info.getScore() + ", Frequency: " + info.getFrequency());
}
}
public static void main(String[] args) {
Stats stats = new Stats();
int[] scores = {85, 90, 75, 85, 100, 90, 95, 85, 100, 75};
stats.recordScores(scores);
stats.printScores();
}
}
class ScoreInfo {
private int score;
private int numStudents;
public ScoreInfo(int aScore) {
score = aScore;
numStudents = 1;
}
public void increment() {
numStudents++;
}
public int getScore() {
return score;
}
public int getFrequency() {
return numStudents;
}
}
2014 Takeaways
- Key Takeaways from This FRQ (Stats & ScoreInfo Classes):
- Understanding Data Storage in Sorted Order:
- The
scoreList(anArrayList<ScoreInfo>) must maintain scores in increasing order. - No duplicate
ScoreInfoobjects should exist for the same score; instead, their frequency is incremented.
- The
- Proper Handling of the
recordMethod:- If the score already exists in the list, increment its frequency.
- If the score does not exist, insert a new
ScoreInfoobject at the correct position to maintain sorted order. - The method should return true if a new score is added, false if an existing score is updated.
- Efficiently Inserting a Score into a Sorted List:
- Use a loop to find the correct insertion point.
- If the list is traversed and no larger value is found, append the score at the end.
- Iterating Over an Array in
recordScores:- The
recordScoresmethod should callrecordfor each score in the array to ensure all scores are properly inserted or updated in the database.
- The
- Encapsulation in Object-Oriented Programming:
ScoreInfoencapsulates a score and its frequency withgetScore(),getFrequency(), andincrement().- The
Statsclass is responsible for managing a collection ofScoreInfoobjects.
- Edge Cases to Consider:
- If
scoreListis empty, the first score should be added directly. - If the new score is less than all existing scores, it should be inserted at index 0.
- If the new score is greater than all existing scores, it should be appended at the end.
- Ensure no duplicate
ScoreInfoobjects exist; only the frequency should be updated.
- If
- Understanding Data Storage in Sorted Order:
- AP Exam Tips Based on This FRQ:
- ✅ Follow the method contract – Return the correct boolean values in
record. - ✅ Think about efficiency – Finding the correct insertion point should ideally take O(n) time.
- ✅ Test edge cases – Try inserting at the beginning, middle, and end of
scoreList. - ✅ Use helper methods when needed –
recordScoresrelies onrecord, reducing redundant code. - ✅ Maintain proper encapsulation – Avoid modifying
ScoreInfodirectly outside its class.
- ✅ Follow the method contract – Return the correct boolean values in
- Skills Tested:
- Working with
ArrayLists, maintaining order, and properly updating data are important skills for the AP CS A exam! 🚀
- Working with
2015 FRQ
public class DiverseArray {
/**
* Computes the sum of the elements in a one-dimensional array.
* @param arr The input array.
* @return The sum of the values in arr.
*/
public static int arraySum(int[] arr) {
int sum = 0;
// Iterate through the array and sum up the elements
for (int num : arr) {
sum += num;
}
return sum;
}
/**
* Computes the row sums of a two-dimensional array.
* @param arr2D The input 2D array.
* @return A 1D array where each element is the sum of a row in arr2D.
*/
public static int[] rowSums(int[][] arr2D) {
int[] rowSums = new int[arr2D.length];
// Iterate over each row and compute its sum
for (int i = 0; i < arr2D.length; i++) {
rowSums[i] = arraySum(arr2D[i]); // Utilize arraySum for row sum computation
}
return rowSums;
}
/**
* Determines if a 2D array is diverse, meaning no two rows have the same sum.
* @param arr2D The input 2D array.
* @return true if all row sums are unique, false otherwise.
*/
public static boolean isDiverse(int[][] arr2D) {
int[] sums = rowSums(arr2D); // Compute the row sums
// Compare each sum with every other sum in the array
for (int i = 0; i < sums.length; i++) {
for (int j = i + 1; j < sums.length; j++) {
if (sums[i] == sums[j]) {
return false; // Duplicate row sums found
}
}
}
return true; // All row sums are unique
}
}
2015b. FRQ
public class HiddenWord {
private String hiddenWord;
/**
* Constructor that initializes the hidden word.
* @param word the hidden word for the game.
*/
public HiddenWord(String word) {
hiddenWord = word;
}
/**
* Generates a hint based on the player's guess.
* @param guess the guessed word, same length as hiddenWord.
* @return a hint string where:
* - Matching letters in the correct position remain unchanged.
* - Letters in the word but wrong position are replaced with "+".
* - Letters not in the word are replaced with "*".
*/
public String getHint(String guess) {
StringBuilder hint = new StringBuilder();
for (int i = 0; i < hiddenWord.length(); i++) {
char guessChar = guess.charAt(i);
char hiddenChar = hiddenWord.charAt(i);
if (guessChar == hiddenChar) {
hint.append(guessChar); // Correct letter & position
} else if (hiddenWord.indexOf(guessChar) != -1) {
hint.append("+"); // Letter exists but wrong position
} else {
hint.append("*"); // Letter does not exist in hiddenWord
}
}
return hint.toString();
}
// Main method for testing
public static void main(String[] args) {
HiddenWord puzzle = new HiddenWord("HARPS");
System.out.println(puzzle.getHint("AAAAA")); // "*****"
System.out.println(puzzle.getHint("HELLO")); // "H****"
System.out.println(puzzle.getHint("HEART")); // "H+AR+"
System.out.println(puzzle.getHint("HARMS")); // "HARP*"
System.out.println(puzzle.getHint("HARPS")); // "HARPS"
}
}
2015c. FRQ
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SparseArray {
private int numRows;
private int numCols;
private List<SparseArrayEntry> entries;
/**
* Removes the column col from the sparse array.
* Precondition: 0 <= col < getNumCols()
*/
public void removeColumn(int col) {
// Use an iterator to remove entries with column index equal to col
Iterator<SparseArrayEntry> iter = entries.iterator();
while (iter.hasNext()) {
SparseArrayEntry entry = iter.next();
if (entry.getCol() == col) {
iter.remove();
}
}
// Adjust column indexes for entries with column index greater than col
for (SparseArrayEntry entry : entries) {
if (entry.getCol() > col) {
entries.set(entries.indexOf(entry),
new SparseArrayEntry(entry.getRow(), entry.getCol() - 1, entry.getValue()));
}
}
// Reduce the number of columns by 1
numCols--;
}
}
// Supporting class for SparseArrayEntry
class SparseArrayEntry {
private int row;
private int col;
private int value;
public SparseArrayEntry(int r, int c, int v) {
row = r;
col = c;
value = v;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public int getValue() {
return value;
}
}
2015 Takeaways:
-
Emphasized core object-oriented programming concepts such as interfaces, encapsulation, list manipulation, and efficient data storage.
- First Question (Diverse Array):
- Involved iterating through 2D arrays and using helper methods to check for unique row sums.
- Second Question (HiddenWord):
- Focused on string processing, evaluating characters based on exact matches, partial matches, or absence in the hidden word.
- Required looping through characters and using conditionals to construct a formatted hint efficiently.
- Skills Reinforced:
- Methodical iteration and condition handling, critical skills for writing structured programs.
- Third and Fourth FRQs:
- SparseArray: Focused on efficient storage of nonzero elements, utilizing a list of objects instead of a full 2D array.
- removeColumn: Introduced safe list modification using iterators and index shifting.
- NumberGroup & MultipleGroups: Tested interfaces and polymorphism, showcasing how an interface can unify different implementations while ensuring flexibility.
- Used lists in MultipleGroups to manage various ranges, highlighting dynamic collections in Java.
- Key Takeaways:
- Reinforced the importance of modular design, encapsulation, and efficient data manipulation.
- These concepts are critical for success in the AP exam and real-world programming. :rocket: