Unit 2 · 22 min

2.10 Implementing String Algorithms

Most string problems are a loop over substrings plus a test, a counter, or a string you build up.

Summary, objectives and course and exam description (CED) codes

Standard string algorithms traverse a string with a loop and substring. You should be able to find whether one or more substrings have a particular property, determine the number of substrings that meet specific criteria, and create a new string with the characters reversed. Compare substrings with equals, never ==, and keep loop bounds inside the string.

By the end of this session you can

  • 2.10.A Develop code for standard and original algorithms that involve strings and determine the result of these algorithms.

2.10.A2.10.A.1

Reviewed against the CED on

Know this already? Jump to the checkpoint.

1LearnThe notes, the traps and how to remember them

1. Traversing a string

String algorithms work by string traversal: a loop visits each position, and substring takes out the part to test. A single character at index i is str.substring(i, i + 1). Indexes run from 0 to length() - 1.

String team = "Hawks";
for (int i = 0; i < team.length(); i++) {
    System.out.println(i + ": " + team.substring(i, i + 1));
}

Output:

0: H
1: a
2: w
3: k
4: s

Watch out (off by one): with i <= team.length(), the last pass asks for substring(5, 6) on a 5-letter string:

String team = "Hawks";
for (int i = 0; i <= team.length(); i++) {
    System.out.println(team.substring(i, i + 1));
}

Output:

H
a
w
k
s
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: Range [5, 6) out of bounds for length 5

The five letters print, then the program crashes on the sixth pass. (The exact wording of the message depends on the Java version.)

2. Does a substring have a property?

There are standard string algorithms to find if one or more substrings have a particular property 2.10.A.1. Two kinds of question:

  • “Is there any substring with the property?” Return true as soon as you find one; return false only after the loop.
  • “Do all substrings have the property?” Return false as soon as one fails; return true only after the loop.

Does a word contain a double letter (the same letter twice in a row)? Each test compares the letter at i with the letter at i + 1, so the loop must stop before the last index.

public static boolean hasDoubleLetter(String word) {
    for (int i = 0; i < word.length() - 1; i++) {
        String here = word.substring(i, i + 1);
        String next = word.substring(i + 1, i + 2);
        if (here.equals(next)) {
            return true;
        }
    }
    return false;
}
System.out.println(hasDoubleLetter("balloon"));
System.out.println(hasDoubleLetter("planet"));
System.out.println(hasDoubleLetter(""));

Output:

true
false
false

Watch out: putting else { return false; } inside the loop would make the method stop after checking only the first pair, so "balloon" would return false.

Is every character a digit? "0123456789".indexOf(ch) is -1 when ch is not a digit.

public static boolean allDigits(String code) {
    for (int i = 0; i < code.length(); i++) {
        String ch = code.substring(i, i + 1);
        if ("0123456789".indexOf(ch) == -1) {
            return false;
        }
    }
    return true;
}
System.out.println(allDigits("2026"));
System.out.println(allDigits("20x6"));

Output:

true
false

3. Counting substrings that meet a criterion

There are standard string algorithms to determine the number of substrings that meet specific criteria 2.10.A.1. Count the vowels in a sentence:

String sentence = "Game over";
int vowels = 0;
for (int i = 0; i < sentence.length(); i++) {
    String ch = sentence.substring(i, i + 1);
    if ("aeiouAEIOU".indexOf(ch) >= 0) {
        vowels++;
    }
}
System.out.println("Vowels: " + vowels);

Output:

Vowels: 4

To count a pattern longer than one letter, use a window of that length. How many times does "an" appear in "banana"? The window substring(i, i + 2) needs i + 2 <= length(), so the loop condition is i <= word.length() - 2.

String word = "banana";
int count = 0;
for (int i = 0; i <= word.length() - 2; i++) {
    if (word.substring(i, i + 2).equals("an")) {
        count++;
    }
}
System.out.println(count);

Output:

2
i substring(i, i + 2) equals “an”? count
0 ba no 0
1 an yes 1
2 na no 1
3 an yes 2
4 na no 2

Watch out (String comparison with ==): this version compiles and runs, but == compares references, and every call to substring here returns a new String object.

String word = "banana";
int count = 0;
for (int i = 0; i < word.length(); i++) {
    if (word.substring(i, i + 1) == "a") {
        count++;
    }
}
System.out.println(count);

Output:

0

4. Reversing a string

There are standard string algorithms to create a new string with the characters reversed 2.10.A.1. Strings are immutable, so you build a new string. Adding each character to the front reverses the order:

String word = "code";
String reversed = "";
for (int i = 0; i < word.length(); i++) {
    reversed = word.substring(i, i + 1) + reversed;
}
System.out.println(reversed);

Output:

edoc
i letter reversed after this iteration
0 c c
1 o oc
2 d doc
3 e edoc

The other way: traverse from the last index down to 0 and add each character to the end. Start at length() - 1, not length().

String word = "code";
String reversed = "";
for (int i = word.length() - 1; i >= 0; i--) {
    reversed += word.substring(i, i + 1);
}
System.out.println(reversed);

Output:

edoc

5. Combining the algorithms

Original algorithms often combine the standard ones. A palindrome reads the same forward and backward: reverse the word, then compare with equals.

public static boolean isPalindrome(String word) {
    String reversed = "";
    for (int i = 0; i < word.length(); i++) {
        reversed = word.substring(i, i + 1) + reversed;
    }
    return reversed.equals(word);
}
System.out.println(isPalindrome("level"));
System.out.println(isPalindrome("lever"));

Output:

true
false

Another combination: remove every space from a string by building a new one that skips spaces.

String phrase = "a b  c";
String result = "";
for (int i = 0; i < phrase.length(); i++) {
    String ch = phrase.substring(i, i + 1);
    if (!ch.equals(" ")) {
        result += ch;
    }
}
System.out.println(result + " (" + result.length() + " letters)");

Output:

abc (3 letters)

Lock it in: memory hooks

  • One lettersubstring(i, i + 1): start at i, stop before i + 1, so you get exactly one character.
  • Window of size kLast start index is length() - k, so loop while i <= length() - k.
  • ReversePut each new letter in front: letter + result.

Common misconceptions

  • "word.substring(i, i + 1) == "a" checks whether the letter is an a."

    Not quite. == compares references. substring creates a new String object, so == is false even when the letter matches. Use .equals("a").

  • "The last index of a string is length()."

    Not quite. Indexes run from 0 to length() - 1. substring(i, i + 1) with i equal to length() throws a StringIndexOutOfBoundsException.

  • "Strings can be changed in place, one letter at a time."

    Not quite. Strings are immutable. To reverse or edit a string, build a new string with concatenation and assign it to a variable.

Exam traps

  • Comparing substrings with == compiles but gives false, so counts come out as 0.
  • i <= str.length() in the loop condition throws a StringIndexOutOfBoundsException on the last pass.
  • Comparing each letter with the next one: stop at length() - 1, not length().
  • Returning false inside the loop on the first mismatch is correct only for an "every" check, never for an "any" check.

2PracticeRecall it, then check yourself

In 30 seconds

  1. Traverse a string with for (int i = 0; i < str.length(); i++) and str.substring(i, i + 1).
  2. To check every piece of length k, loop i from 0 while i <= str.length() - k and use substring(i, i + k).
  3. Property check: return or set a boolean as soon as one substring matches (or as soon as one fails).
  4. Counting: a counter starts at 0 before the loop; add 1 inside an if.
  5. Reverse: build a new string, adding each character to the front, or traverse from the last index down to 0.
  6. Compare strings with equals. == compares references.

Cover this list, say the points out loud, then take the checkpoint without scrolling back up.

Checkpoint · 5 questions

Checkpoint: Implementing String Algorithms

Pick an answer to mark it. Every answer is explained, and you can try any question again. Your saved score counts first tries only, and stays in this browser.

  1. 1 Consider the following code segment. What is printed as a result of executing the code segment? 2.10.A.1
    String s = "aabbba";
    int count = 0;
    for (int i = 0; i < s.length() - 1; i++) {
        if (s.substring(i, i + 1).equals(s.substring(i + 1, i + 2))) {
            count++;
        }
    }
    System.out.println(count);
    Show answer

    Answer: D. The loop compares each letter with the next one: aa (match), ab, bb (match), bb (match), ba. That is 3 matching pairs. Answering 2 counts the runs of repeated letters instead of the pairs; "bbb" contains two overlapping pairs.

  2. 2 Consider the following code segment. What is printed as a result of executing the code segment? 2.10.A.1
    String w = "stop";
    String r = "";
    for (int i = 0; i < w.length(); i += 2) {
        r = w.substring(i, i + 1) + r;
    }
    System.out.println(r);
    Show answer

    Answer: B. The loop visits indexes 0 and 2 only, taking "s" and then "o". Each new letter is placed in front of r, so r becomes "s" and then "os". "so" adds letters to the end instead of the front, and "pots" reverses every letter, ignoring i += 2.

  3. 3 Consider the following code segment. What is printed as a result of executing the code segment? 2.10.A.1
    String word = "noon";
    int n = 0;
    for (int i = 0; i < word.length(); i++) {
        if (word.substring(i, i + 1) == "n") {
            n++;
        }
    }
    System.out.println(n);
    Show answer

    Answer: D. == compares object references, and each call to substring here creates a new String object, so the comparison is false every time and n stays 0. Answering 2 assumes == compares the characters, which equals does. Comparing two references with == is legal, so the code compiles.

  4. 4 The String s has been declared and initialized. A loop uses s.substring(i, i + 3).equals("cat") to count every place where "cat" appears in s. Which loop header checks every possible position without throwing an exception? 2.10.A.1
    Show answer

    Answer: A. A window of 3 characters starting at i needs i + 3 <= s.length(), so the last start index is s.length() - 3, and <= includes it. i < s.length() - 3 skips the last possible position (an off by one error), so "cat" at the very end is missed. The other two headers go past the end and throw a StringIndexOutOfBoundsException.

  5. 5 The following method is intended to return true if its parameter contains at least one digit character, and false otherwise. For which of the following calls does the method NOT return the intended value? 2.10.A.1
    public static boolean hasDigit(String s) {
        for (int i = 0; i < s.length(); i++) {
            if ("0123456789".indexOf(s.substring(i, i + 1)) >= 0) {
                return true;
            } else {
                return false;
            }
        }
        return false;
    }
    Show answer

    Answer: C. The else returns false after checking only the first character, so the method decides from the first letter alone. For "room5" the first letter is not a digit and the method returns false, although the string contains 5. "7up" starts with a digit (true, correct); "" and "abcdef" correctly give false.

3PrevailLock it in for exam day

By the numbers

Name each list from memory, then reveal it to check. Each list shows how many items to recall.

  • Standard string algorithms three algorithms CED 2.10.A.1
    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

Key terms: flip the cards

Read the term, say the definition out loud, then flip to check. Struggling a little to remember is what makes it stick.

  • String traversaltap to flip

    Visiting the characters or substrings of a string one position at a time with a loop, usually with substring(i, i + 1).

    Example and CED codes
  • Stringtap to flip

    A class whose objects hold a sequence of characters. String is a reference type in java.lang, and String objects are immutable.

    Example and CED codes
  • Indextap to flip

    The position of a character in a String, counted from 0. Valid indices run from 0 to length() - 1.

    Example and CED codes
  • for looptap to flip

    An iterative statement whose header has three parts: the initialization (runs once), the Boolean expression (checked before each iteration) and the update (after each iteration).

    Example and CED codes
  • Off by one errortap to flip

    An error in which a loop runs one time too many or one time too few, often from < versus <= or a wrong starting value.

    Example and CED codes
  • Reference equality (== versus equals)tap to flip

    Using == or != on object references checks whether they refer to the same object. A class's equals method checks whether two objects are equivalent.

    Example and CED codes

Questions students ask

How do you loop through a string in Java for the AP® exam?

Use for (int i = 0; i < str.length(); i++) and get each character as a one-letter string with str.substring(i, i + 1). These methods are on the Java Quick Reference.

How do you count occurrences of a letter in a string?

Traverse the string, compare each one-letter substring with the target using equals, and add 1 to a counter when they match.

How do you reverse a string in Java without library helpers?

Start with an empty string and traverse the original. Add each character to the front of the result (result = letter + result), or loop from the last index down to 0 and add each character to the end.

Why does my string loop throw StringIndexOutOfBoundsException?

The loop goes one index too far. The last valid start index for substring(i, i + k) is length() - k, so the loop condition must stop there.

Was this page helpful?

No names are ever shown, and every public comment is checked by us first. Please do not include personal details. To get a reply, email [email protected].

↑ Top

Enlarged view of the selected figure