Methods, Arrays & Strings

Practice: Array & String Algorithms

15 min Lesson 10 of 14

Practice: Array & String Algorithms

You have reached the final lesson of this tutorial. Everything you have learned — methods, loops, arrays, and strings — comes together here. Rather than introducing new syntax, this lesson is about thinking algorithmically: reading a problem, choosing the right data structure, and writing clean, correct Java that a teammate can understand.

We will work through four classic problems that appear in interviews, coding challenges, and real software all the time:

  1. Reverse an array in place
  2. Find the maximum value in an array
  3. Count occurrences of a character in a string
  4. Check whether a string is a palindrome
Why these four? Each one teaches a different pattern you will reuse constantly: two-pointer swapping, a running maximum, character-by-character scanning, and meet-in-the-middle comparison. Learn the pattern, not just the answer.

1. Reverse an Array In Place

Reversing in place means we do not create a second array; we swap elements within the original one. The technique is called the two-pointer approach: one pointer starts at index 0 and another at the last index. They march toward each other, swapping as they go, and stop when they meet.

public static void reverseArray(int[] arr) { int left = 0; int right = arr.length - 1; while (left < right) { // swap arr[left] and arr[right] int temp = arr[left]; arr[left] = arr[right]; arr[right] = temp; left++; right--; } } // usage int[] numbers = {1, 2, 3, 4, 5}; reverseArray(numbers); System.out.println(Arrays.toString(numbers)); // [5, 4, 3, 2, 1]
Why not create a new array? Allocating a second array uses extra memory proportional to the input size (called O(n) space). The two-pointer approach uses only one extra variable (temp), which is constant — O(1) space. For large arrays this matters.

2. Find the Maximum Value

The standard pattern: assume the first element is the maximum, then walk the rest of the array updating your assumption whenever you find something larger.

public static int findMax(int[] arr) { if (arr.length == 0) { throw new IllegalArgumentException("Array must not be empty"); } int max = arr[0]; // start with the first element for (int i = 1; i < arr.length; i++) { if (arr[i] > max) { max = arr[i]; } } return max; } // usage int[] scores = {42, 17, 99, 56, 8}; System.out.println("Max: " + findMax(scores)); // Max: 99
Always guard against an empty array. If you call arr[0] on an empty array, Java throws an ArrayIndexOutOfBoundsException at runtime. A quick length check with a meaningful exception message is much easier to debug than a cryptic stack trace.

3. Count Occurrences of a Character

The String class stores characters in order. To count how many times a given character appears, loop over every position with charAt(i) and increment a counter when there is a match.

public static int countOccurrences(String text, char target) { int count = 0; for (int i = 0; i < text.length(); i++) { if (text.charAt(i) == target) { count++; } } return count; } // usage String sentence = "banana"; System.out.println(countOccurrences(sentence, 'a')); // 3 System.out.println(countOccurrences(sentence, 'n')); // 2
Case sensitivity matters. 'A' and 'a' are different characters in Java. If you want a case-insensitive count, convert both the string and the target to the same case before comparing: text.toLowerCase().charAt(i) and Character.toLowerCase(target).

4. Check Whether a String Is a Palindrome

A palindrome reads the same forwards and backwards — "racecar", "level", "madam". The cleanest approach mirrors the array-reverse technique: compare the character at position left with the character at position right. If every pair matches until the pointers meet, it is a palindrome.

public static boolean isPalindrome(String text) { // strip non-letter characters and convert to lowercase for a fair comparison String cleaned = text.toLowerCase().replaceAll("[^a-z0-9]", ""); int left = 0; int right = cleaned.length() - 1; while (left < right) { if (cleaned.charAt(left) != cleaned.charAt(right)) { return false; // mismatch found — not a palindrome } left++; right--; } return true; // all pairs matched } // usage System.out.println(isPalindrome("racecar")); // true System.out.println(isPalindrome("A man a plan a canal Panama")); // true System.out.println(isPalindrome("hello")); // false
Cleaning the input first is a deliberate design decision. Real-world palindrome problems (and most interview questions) treat spaces and punctuation as irrelevant. By calling replaceAll with a regex once at the start, the comparison loop stays simple and focused.

Putting It All Together

Notice the shared patterns across all four algorithms:

  • Two pointers — used in both the reverse and palindrome problems. Whenever you need to compare or swap from both ends of a sequence, reach for this pattern.
  • Running result — used in the max and count problems. Initialise a variable before the loop, update it inside, return it after.
  • Guard clauses — check edge cases (empty input, null) at the very top of the method. Let the happy path run without defensive clutter.
  • Descriptive method namesisPalindrome and findMax tell a reader what the method does before they read a single line of its body.
Practice habit: after you write any algorithm, test it with at least three inputs — a normal case, an edge case (empty string, single element, even-length vs odd-length), and a case where the answer is false or zero. These three tests catch the vast majority of off-by-one bugs.

Summary

In this lesson you implemented four foundational algorithms entirely from scratch: reversing an array with the two-pointer swap, finding a maximum with a running variable, counting characters with a simple scan, and detecting palindromes with a two-pointer comparison. These patterns recur throughout computer science. Understand them well and you will recognise them — sometimes in disguise — in far more complex problems ahead.