Computer Science A
2019 FRQ 3 - Delimiters
- 2019 AP CSA FRQ #3 -- Delimiters
- Examples of Delimiters
- The
DelimitersClass - Code Runner Challenge
- Popcorn Hack 1: String Comparison
- Code Runner Challenge
- Drag and Drop: Order the
isBalancedAlgorithm - Build the Algorithm
- Available Steps
- Correct Order
- Popcorn Hack 2: The Order Trap
- Popcorn Hack 3: Loop and Return Logic
- isBalanced -- Step-by-Step Visualizer
- Delimiter Sequence
- Open Counter
2019 AP CSA FRQ #3 -- Delimiters
Master ArrayList manipulation through interactive challenges on delimiter parsing & balancing
ArrayList<String>, iterate through arrays, compare strings with .equals(), and track state using accumulators -- all core AP CSA concepts.
(/) or <B>/</B>. You will write two methods: one to extract delimiters from a token array, and one to check if they are balanced.
Examples of Delimiters
| Type | Open | Close | Valid Example | Invalid Example |
|---|---|---|---|---|
| Math | ( |
) |
(x + y) * 5 |
(x + (y) – more opens than closes |
| HTML | <B> |
</B> |
<B>bold</B> |
<B>bold</UB> – mismatched close |
The Delimiters Class
Code Runner Challenge
Part (a) -- Complete the getDelimitersList method
View IPYNB Source
public class Delimiters {
private String openDel;
private String closeDel;
public Delimiters(String open, String close) { ... }
public ArrayList<String> getDelimitersList(String[] tokens) { /* Part A */ }
public boolean isBalanced(ArrayList<String> delimiters) { /* Part B */ }
}
Part A – getDelimitersList
Given a String[] tokens array containing text and delimiters, return an ArrayList<String> with only the open and close delimiters, in their original order.
Example: openDel = "(", closeDel = ")", tokens = ["(", "x + y", ")", "* 5"]
Returns ["(", ")"]
Example: openDel = "<q>", closeDel = "</q>", tokens = ["<q>", "yy", "</q>", "zz", "</q>"]
Returns ["<q>", "</q>", "</q>"]
Popcorn Hack 1: String Comparison
Inside getDelimitersList, you compare each token to openDel and closeDel. Which comparison is correct?
if (tokens[i] == openDel || tokens[i] == closeDel)
if (tokens[i].equals(openDel) || tokens[i].equals(closeDel))
if (tokens[i].compareTo(openDel) && tokens[i].compareTo(closeDel))
if (tokens.contains(openDel) || tokens.contains(closeDel))
Code Runner Challenge
Part (B) -- Complete the isBalanced method
View IPYNB Source
// CODE_RUNNER: Part (a) -- Complete the getDelimitersList method
import java.util.ArrayList;
public class Delimiters {
private String openDel;
private String closeDel;
public Delimiters(String open, String close) {
openDel = open;
closeDel = close;
}
/** Part (a): Returns an ArrayList of delimiters from the array tokens */
public ArrayList<String> getDelimitersList(String[] tokens) {
ArrayList<String> result = new ArrayList<String>();
for (int i = 0; i < tokens.length; i++) {
if (tokens[i].equals(openDel) || tokens[i].equals(closeDel)) {
result.add(tokens[i]);
}
}
return result;
}
public static void main(String[] args) {
// Test with parentheses
Delimiters d1 = new Delimiters("(", ")");
String[] tokens1 = {"(", "x + y", ")", "* 5"};
System.out.println("Test 1: " + d1.getDelimitersList(tokens1));
// Expected: [(, )]
// Test with HTML tags
Delimiters d2 = new Delimiters("<q>", "</q>");
String[] tokens2 = {"<q>", "yy", "</q>", "zz", "</q>"};
System.out.println("Test 2: " + d2.getDelimitersList(tokens2));
// Expected: [<q>, </q>, </q>]
}
}
Delimiters.main(null);
Part B – isBalanced
Returns true when delimiters are balanced. Two rules:
- At no point while scanning left-to-right are there more close delimiters than open delimiters.
- Total open delimiters equals total close delimiters.
Drag and Drop: Order the isBalanced Algorithm
Build the Algorithm
Drag each step into the correct order to implement isBalanced
Available Steps
Correct Order
Popcorn Hack 2: The Order Trap
Why can you not simply count all opens and all closes separately and check if they are equal?
It would be too slow -- O(n^2)
) ( would pass -- closes before opens
You cannot count Strings in Java
ArrayList does not support counting
Popcorn Hack 3: Loop and Return Logic
In isBalanced, what should happen inside the loop when openCount becomes negative?
isValid = false and continue the loop
false immediately -- no need to check further
openCount to 0 and keep going
IllegalStateException
Live Delimiter Visualizer
Watch isBalanced execute step-by-step. Select a delimiter sequence and step through the algorithm to see how the counter changes at each position.
isBalanced -- Step-by-Step Visualizer
See how the counter rises and falls as we scan delimiters left-to-right
Delimiter Sequence
Open Counter
// CODE_RUNNER: Part (B) -- Complete the isBalanced method
import java.util.ArrayList;
public class Delimiters {
private String openDel;
private String closeDel;
public Delimiters(String open, String close) {
openDel = open;
closeDel = close;
}
/** Part (a): Extract delimiters from tokens */
public ArrayList<String> getDelimitersList(String[] tokens) {
ArrayList<String> result = new ArrayList<String>();
for (int i = 0; i < tokens.length; i++) {
if (tokens[i].equals(openDel) || tokens[i].equals(closeDel)) {
result.add(tokens[i]);
}
}
return result;
}
/** Part (b): Check if delimiters are balanced */
public boolean isBalanced(ArrayList<String> delimiters) {
int openCount = 0;
int closeCount = 0;
for (int i = 0; i < delimiters.size(); i++) {
if (delimiters.get(i).equals(openDel)) {
openCount++;
} else {
closeCount++;
}
// Rule 1: At no point should closes exceed opens
if (closeCount > openCount) {
return false;
}
}
// Rule 2: Final count of opens must equal closes
return openCount == closeCount;
}
public static void main(String[] args) {
Delimiters d = new Delimiters("<sup>", "</sup>");
// Test 1: Balanced -- expected true
ArrayList<String> t1 = new ArrayList<>();
t1.add("<sup>"); t1.add("<sup>"); t1.add("</sup>");
t1.add("<sup>"); t1.add("</sup>"); t1.add("</sup>");
System.out.println("Test 1 (expect true): " + d.isBalanced(t1));
// Test 2: Close before open -- expected false (Rule 1)
ArrayList<String> t2 = new ArrayList<>();
t2.add("<sup>"); t2.add("</sup>"); t2.add("</sup>"); t2.add("<sup>");
System.out.println("Test 2 (expect false): " + d.isBalanced(t2));
// Test 3: Single close -- expected false (Rule 1)
ArrayList<String> t3 = new ArrayList<>();
t3.add("</sup>");
System.out.println("Test 3 (expect false): " + d.isBalanced(t3));
// Test 4: Unequal counts -- expected false (Rule 2)
ArrayList<String> t4 = new ArrayList<>();
t4.add("<sup>"); t4.add("<sup>"); t4.add("</sup>");
System.out.println("Test 4 (expect false): " + d.isBalanced(t4));
}
}
Delimiters.main(null);
Delimiter Balance Runner
Use the arrow keys (or A/D) to move your collector left and right. Delimiters fall from the sky. You must catch them in the correct order to build a balanced sequence. Catching a delimiter that breaks the balance costs a life. The sequence must be balanced when the wave ends – if not, you lose a life and retry. Survive all waves to win.
This game reinforces the exact logic of isBalanced: you must track open vs close counts in real time, and order matters.
Delimiter Balance Runner
Move with arrow keys or A/D. Catch delimiters in the right order to build balanced sequences.
Final Knowledge Check
AP Exam Readiness Quiz -- 5 Questions
Test your understanding of everything in this FRQ
AP Scoring Guidelines
Official Scoring Rubric -- 9 Points Total
Use this to self-grade your solution
ArrayList<String>+1 Accesses all elements in array
tokens (no bounds errors)+1 Compares strings with both instance variables using
.equals() in a loop+1 Adds delimiters into ArrayList in original order
+1 Accesses all elements in ArrayList
delimiters (no bounds errors)+1 Compares strings with instance variables and updates accumulator(s)
+1 Identifies and returns appropriate boolean for one rule
+1 Identifies and returns appropriate boolean values for all cases
== for string comparison instead of .equals()Accessing array elements as ArrayList:
tokens.get(i) instead of tokens[i]Not returning
false inside the loop when closes exceed opensInitializing the accumulator inside the loop instead of before it