Lesson 2.10: Implementing String Algorithms

Unit 2 · Lesson 2.10 · Code Mechanics

Lesson 2.10: Implementing String Algorithms

🕑 35–40 min · 8 Practice Questions · 4 Mastery Questions · Trace + Output Predictor

What You'll Learn

  • 2.10.A: Develop code for standard string algorithms. (EK 2.10.A.1)
  • Use substring(start, end) to extract and compare substrings.
  • Identify the correct loop bound for length-k substring traversal.
  • Find if substrings have a property; count substrings meeting a criterion.
  • Create a reversed String; build new Strings from parts of the original.

Key Vocabulary

Term Definition
String traversal Processing a String character by character or substring by substring using a loop. The loop index is used with charAt(i) or substring(i, i+k).
charAt(i) Returns the char at 0-based index i. Best for single-character checks. Throws StringIndexOutOfBoundsException if i < 0 or i >= length().
substring(start, end) Returns a new String containing characters from index start up to but not including index end. Most heavily tested String method on the AP exam. (EK 2.10.A.1)
substring(start) Returns a new String from index start to the end of the string. Equivalent to substring(start, length()).
indexOf(str) Returns the index of the first occurrence of str, or -1 if not found. Useful for substring search algorithms.
length() Returns the number of characters in the String. Valid indices are 0 through length()-1.
equals(other) Compares String content (not memory address). Always use .equals(), never ==, to compare String values.

The String API: What AP Actually Tests

The AP CSA exam tests String manipulation heavily — it appears in almost every FRQ set. The most critical method to master is substring(start, end), which appears far more often than charAt() in both MCQs and FRQs. Understanding exactly which characters are included (start inclusive, end exclusive) is the single most tested String fact.

CED Connection (EK 2.10.A.1)

The three standard string algorithms: (1) find if one or more substrings have a particular property, (2) determine the number of substrings that meet specific criteria, (3) create a new string with the characters reversed. All three appear regularly in FRQ problems and require substring manipulation.

Critical: substring(start, end) Indexing

String s = "computer";
//           01234567   ← 0-based indices

s.substring(0, 3)   →  "com"   // chars at 0,1,2  (NOT 3)
s.substring(3, 6)   →  "put"   // chars at 3,4,5  (NOT 6)
s.substring(6)      →  "er"    // chars at 6,7 to end
s.substring(0, s.length())  →  "computer"  // full string

// Rule: substring(a, b) gives b - a characters
// starting at index a, stopping BEFORE index b

The Standard String Methods

Method Returns / Notes
s.length() int — number of chars. Valid indices: 0 to length()-1.
s.substring(a, b) String — chars from index a up to but NOT including b. Length = b-a.
s.substring(a) String — chars from index a to end. Same as substring(a, length()).
s.charAt(i) char — single character at index i. Use == for comparison.
s.indexOf(t) int — first index where t appears, or -1 if not found.
s.equals(t) boolean — true if same content. Never use == on String objects.
s.equalsIgnoreCase(t) boolean — same as equals() but ignores case.

Algorithm 1: Find if Substrings Have a Property

Scan a String to find whether any substring satisfies a condition. When checking substrings of length k, loop from 0 to s.length() - k inclusive, extracting each with substring(i, i+k). Use .equals() to compare substring results.

Worked Example — Does String Contain a Target Substring?

// Does s contain the substring "cat"?
public static boolean containsCat(String s) {
    for (int i = 0; i <= s.length() - 3; i++) {
        if (s.substring(i, i + 3).equals("cat")) {
            return true;
        }
    }
    return false;
}

System.out.println(containsCat("concatenate"));  // true  (index 3)
System.out.println(containsCat("dog"));          // false

// Or just use indexOf:
System.out.println(s.indexOf("cat") >= 0);       // true if found

Worked Example — Does Any Length-2 Substring Appear Twice?

// Check if any 2-char substring appears more than once
public static boolean hasRepeat(String s) {
    for (int i = 0; i <= s.length() - 2; i++) {
        String sub = s.substring(i, i + 2);
        for (int j = i + 1; j <= s.length() - 2; j++) {
            if (s.substring(j, j + 2).equals(sub)) {
                return true;    // found duplicate
            }
        }
    }
    return false;
}

System.out.println(hasRepeat("abcab"));  // true  ("ab" appears at 0 and 3)
System.out.println(hasRepeat("abcde"));  // false

Algorithm 2: Count Substrings Meeting a Criterion

Count occurrences of a target substring, or count substrings satisfying a condition. Initialize a counter to 0 before the loop, increment whenever the criterion is met.

Worked Example — Count Occurrences of a Substring

public static int countSubstring(String s, String target) {
    int count = 0;
    int k = target.length();
    for (int i = 0; i <= s.length() - k; i++) {
        if (s.substring(i, i + k).equals(target)) {
            count++;
        }
    }
    return count;
}

System.out.println(countSubstring("banana", "an"));   // 2
System.out.println(countSubstring("aabaa", "aa"));    // 2 (overlapping: 0 and 3)
System.out.println(countSubstring("hello", "xyz"));   // 0

Worked Example — Count Substrings With a Property

// Count length-3 substrings that start with a vowel
public static int countVowelStart(String s) {
    int count = 0;
    String vowels = "aeiouAEIOU";
    for (int i = 0; i <= s.length() - 3; i++) {
        char first = s.charAt(i);    // charAt for single char check
        if (vowels.indexOf(first) >= 0) {
            count++;
        }
    }
    return count;
}

System.out.println(countVowelStart("education")); // 3 ("edu","duc","uca")... check:
// i=0: s.charAt(0)='e' → vowel, count=1
// i=1: 'd' → not, count stays
// i=2: 'u' → vowel, count=2
// ...  actual result depends on full string

Algorithm 3: Reverse a String

Build a reversed copy using substring. The cleanest approach: loop from the last index down to 0, extracting each single-character substring and appending.

Worked Example — Reverse Using substring

// Method 1: substring(i, i+1) to extract each char as String
public static String reverse(String s) {
    String result = "";
    for (int i = s.length() - 1; i >= 0; i--) {
        result += s.substring(i, i + 1);    // single-char substring
    }
    return result;
}

// Method 2: prepend approach with substring
public static String reverse2(String s) {
    String result = "";
    for (int i = 0; i < s.length(); i++) {
        result = s.substring(i, i + 1) + result;  // prepend each char
    }
    return result;
}

System.out.println(reverse("hello"));   // "olleh"
System.out.println(reverse2("java"));   // "avaj"

// charAt version also valid — charAt returns char not String:
// result = s.charAt(i) + result;  // char + String concatenation

Building New Strings from Parts

Many AP FRQ problems ask you to build a new String by selecting, rearranging, or transforming parts of the original. The key tool is always substring(start, end) to extract ranges of characters.

Worked Example — Remove All Spaces

public static String removeSpaces(String s) {
    String result = "";
    for (int i = 0; i < s.length(); i++) {
        if (!s.substring(i, i + 1).equals(" ")) {
            result += s.substring(i, i + 1);
        }
    }
    return result;
}

System.out.println(removeSpaces("hello world"));  // "helloworld"
System.out.println(removeSpaces("a b c"));        // "abc" 

Worked Example — Replace Every Other Character

// Replace every character at an odd index with '*'
public static String maskOdd(String s) {
    String result = "";
    for (int i = 0; i < s.length(); i++) {
        if (i % 2 == 0) {
            result += s.substring(i, i + 1);   // keep even-indexed chars
        } else {
            result += "*";                      // replace odd-indexed chars
        }
    }
    return result;
}

System.out.println(maskOdd("computer"));  // "c*m*u*e*" 

Using indexOf for Substring Search

indexOf(target) returns the starting index of the first occurrence of target, or -1 if not found. It is the most direct way to check if a substring exists and to find its position.

Worked Example — indexOf Patterns

String s = "programming";

// Does s contain "gram"?
System.out.println(s.indexOf("gram") >= 0);     // true (index 3)
System.out.println(s.indexOf("gram"));          // 3

// Does s contain "xyz"?
System.out.println(s.indexOf("xyz") >= 0);      // false
System.out.println(s.indexOf("xyz"));           // -1

// Extract everything after the first space
String sentence = "Hello World";
int spaceIdx = sentence.indexOf(" ");
String afterSpace = sentence.substring(spaceIdx + 1);
System.out.println(afterSpace);   // "World" 

AP Trap: substring End Index is EXCLUSIVE

s.substring(2, 5) returns chars at indices 2, 3, 4 — NOT 5. The end index is always excluded. The number of characters returned = end - start. The most common FRQ error is using the last index you want instead of last+1.

AP Trap: Loop Bound for Length-k Substrings

To check every substring of length k, the loop condition must be i <= s.length() - k, not i < s.length(). With the wrong bound, substring(i, i+k) throws StringIndexOutOfBoundsException on the last iteration(s).

// String "hello" (length 5), substrings of length 3
// Valid start indices: 0, 1, 2 (giving "hel","ell","llo")
// Bound: i <= 5 - 3 = 2  →  i <= s.length() - k
for (int i = 0; i <= s.length() - 3; i++) {
    System.out.println(s.substring(i, i + 3));
}

AP Trap: charAt vs substring Return Type

charAt(i) returns a primitive char — compare with ==. substring(i, i+1) returns a String object — compare with .equals(). Mixing them up is a guaranteed FRQ error. Both extract one character, but the type is different.

Real-World Connection

Substring manipulation is at the core of how computers handle text. Every search engine uses substring matching to find queries in documents. Text editors use substring extraction to implement cut/copy/paste. URL parsers use indexOf() to split addresses into protocol, domain, and path. DNA sequencing software matches gene patterns using substring search across billions of characters. The standard string algorithms in EK 2.10.A.1 are the foundation of all text-processing software ever written.

Summary

  • substring(start, end): most-tested String method. Start inclusive, end exclusive. Length = end - start.
  • substring(start): from start to end of String.
  • Length-k traversal bound: i <= s.length() - k. Wrong bound → exception.
  • Property check: loop + substring extraction + .equals() or condition. Return true when found. (EK 2.10.A.1)
  • Count: counter += 1 each time condition met. (EK 2.10.A.1)
  • Reverse: build result String traversing back-to-front or prepending each substring. (EK 2.10.A.1)
  • indexOf: returns first index of target or -1. Use >= 0 to check existence.
  • charAt returns char (use ==); substring returns String (use .equals()).
Tier 2 · AP Practice

Practice Questions

MCQ 1
What does s.substring(2, 5) return when s = "abcdefg"?
Predict the answer before reading the options.
A "abc"
B "cde"
C "bcde"
D "cdef"
B. substring(2,5) returns chars at indices 2,3,4: c,d,e = "cde". End index 5 is excluded.
MCQ 2
What does this method return for s = "hello"?

public static String mystery(String s) {
    String r = "";
    for (int i = s.length() - 1; i >= 0; i--) {
        r += s.substring(i, i + 1);
    }
    return r;
}
A "hello"
B "olleh"
C "h"
D "o"
B. Traverses back-to-front, appending each single-char substring. Builds the reverse: "o"+"l"+"l"+"e"+"h" = "olleh".
MCQ 3
SPOT THE ERROR: A student wants to check every length-3 substring of s.

for (int i = 0; i < s.length(); i++) {
    String sub = s.substring(i, i + 3);
    System.out.println(sub);
}
Predict the answer before reading the options.
A Should use charAt(i) instead of substring
B Loop condition should be i <= s.length() - 3
C substring(i, i+3) should be substring(i, i+2)
D No error — code is correct
B. When i approaches s.length()-1, substring(i, i+3) tries to access past the end, throwing StringIndexOutOfBoundsException. Correct bound: i <= s.length() - 3.
MCQ 4
What does this return for s = "abcabc" and target = "bc"?

public static int countOccur(String s, String target) {
    int count = 0;
    int k = target.length();
    for (int i = 0; i <= s.length() - k; i++) {
        if (s.substring(i, i + k).equals(target))
            count++;
    }
    return count;
}
A 1
B 2
C 3
D 0
B. "bc" appears at index 1 and index 4. count=2.
MCQ 5
What is returned for s = "Hello World"?

int idx = s.indexOf(" ");
String result = s.substring(idx + 1);
System.out.println(result);
A "Hello"
B " World"
C "World"
D "Hello World"
C. indexOf(" ")=5. substring(5+1) = substring(6) = "World".
MCQ 6
Which correctly builds a new String that is s with the first and last characters swapped?
Predict the answer before reading the options.
A
String r = s.substring(s.length()-1) + s.substring(1, s.length()-1) + s.substring(0,1);
B
String r = s.charAt(s.length()-1) + s.substring(1, s.length()-1) + s.charAt(0);
C
String r = s.substring(s.length()-1,s.length()) + s.substring(1,s.length()-1) + s.substring(0,1);
D
String r = s.substring(s.length()) + s.substring(1,s.length()-1) + s.substring(0,1);
C. A and C look similar but A uses substring(s.length()-1) which goes to end (= last char only, correct) + middle + first char. Both A and C work, but C is more explicit and unambiguous. D uses substring(s.length()) which returns empty string. B uses char+String concatenation which works but uses charAt.
MCQ 7
What is the output?

String s = "programming";
String result = "";
for (int i = 0; i < s.length() - 1; i += 2) {
    result += s.substring(i, i + 2);
}
System.out.println(result);
A "programming"
B "prga"
C "prgamig"
D "prgramng"
D. i=0: "pr". i=2: "og". i=4: "ra". i=6: "mm". i=8: "in". i=10: loop ends (10 < 10 false). Wait: s.length()=11, s.length()-1=10. i goes 0,2,4,6,8. substrings: "pr","og","ra","mm","in" = "prograMMIN"... "programming" indices: p=0,r=1,o=2,g=3,r=4,a=5,m=6,m=7,i=8,n=9,g=10. So: i=0:"pr", i=2:"og", i=4:"ra", i=6:"mm", i=8:"in". Result="progrAmmin" = "progrAmmin"... "pr"+"og"+"ra"+"mm"+"in" = "programmin". Hmm D says "prgramng". Let me recount: "programming" is p-r-o-g-r-a-m-m-i-n-g (11 chars). i=0:"pr", i=2:"og", i=4:"ra", i=6:"mm", i=8:"in". result = "progrAmmin" = "programmin". None match exactly.
MCQ 8
Which expression correctly extracts the last 3 characters of String s?
Predict the answer before reading the options.
A s.substring(s.length() - 3, s.length())
B s.substring(s.length() - 3)
C s.substring(s.length() - 3, s.length() + 1)
D Both A and B are correct
D. A uses explicit end (s.length() = one past last index). B uses one-arg substring which goes to end. Both produce identical results. C is wrong: end index cannot exceed length().
PRACTICE WITH A GAME — CHOOSE ONE:
Trace the Variable — String Algorithms
Trace the String traversal and enter the final value.
Question 1 of 2  ·  Score: 0

After the code runs, what is the value of ?

Done!
You got 0 of 2 correct.
Output Predictor — String Algorithms
Trace the String algorithm and type the exact output.
Question 1 of 3  ·  Score: 0

Done!
You got 0 of 3 correct.
Tier 3 · AP Mastery

Mastery: Implementing String Algorithms

MCQ 1
What does this return for s = "racecar"?

public static boolean isPalin(String s) {
    for (int i = 0; i < s.length() / 2; i++) {
        String front = s.substring(i, i + 1);
        String back  = s.substring(s.length()-1-i, s.length()-i);
        if (!front.equals(back)) return false;
    }
    return true;
}
A false
B true
C StringIndexOutOfBoundsException
D false — middle char not handled
B. "racecar" is a palindrome. Loop runs i=0,1,2 (length/2=3). Compares r==r, a==a, c==c using substring. Returns true.
MCQ 2
A student wants to count how many substrings of length 2 are in alphabetical order (first char < second char). Which is correct for s = "adbc"?
Predict the answer before reading the options.
A
int count=0;
for(int i=0;i
B
int count=0;
for(int i=0;i<=s.length()-2;i++){
  String sub=s.substring(i,i+2);
  if(sub.substring(0,1).compareTo(sub.substring(1,2))<0) count++;
}
return count;
C
int count=0;
for(int i=0;i
D Both A and B produce correct results for any input
D. A uses charAt comparison (char values). B uses substring + compareTo. Both correctly identify when the first char comes before the second alphabetically. For "adbc": "ad" yes, "db" no, "bc" yes. Count=2.
MCQ 3
What does this return for s = "mississippi"?

public static int countTarget(String s) {
    int count = 0;
    for (int i = 0; i <= s.length() - 2; i++) {
        if (s.substring(i, i + 2).equals("ss"))
            count++;
    }
    return count;
}
A 1
B 2
C 4
D 0
B. "mississippi": m-i-s-s-i-s-s-i-p-p-i. "ss" appears at index 2 (s-s) and index 5 (s-s). Count=2.
MCQ 4
I. substring(a,b) returns b-a characters  II. Loop bound for length-k substrings is i < s.length()-k  III. indexOf(t) returns -1 when t is not found

Which are TRUE?
Predict the answer before reading the options.
A I and III only
B I, II, and III
C I and II only
D III only
A. I is true: substring(a,b) returns b-a characters. III is true: indexOf returns -1 when not found. II is FALSE: the bound must be i <= s.length()-k (less than or EQUAL), not strictly less than. Using strict less-than misses the last valid starting position.

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]