Back to Stream Practice: String & Character
Q9Question 9 of 11

Check if a string is a palindrome using streams

Key Concepts
  • IntStream.range(0, n/2).allMatch(i -> s.charAt(i) == s.charAt(n-1-i)) checks a palindrome by comparing mirrored pairs
  • Only half the string is iterated because once the first half matches the second half, the whole string is confirmed
  • allMatch short-circuits on the first mismatch, returning false immediately
  • Normalize input by lowercasing and stripping non-letters for real-world palindrome checks
  • Empty and single-character strings are palindromes, handled naturally by range(0, 0) returning true
  • This is more efficient than reversing and comparing because it allocates nothing and stops early

Definition

IntStream.range(0, n/2).allMatch(i -> s.charAt(i) == s.charAt(n-1-i)) checks whether a string is a palindrome by comparing each character with its mirror.
  • Palindrome is a string that reads the same forwards and backwards.
  • IntStream.range(0, n/2) generates indices for the first half of the string.
  • allMatch returns true only if every mirrored pair matches, and short-circuits on the first mismatch.
  • Normalization means lowercasing and stripping non-letters before checking, so mixed-case input and punctuation do not cause false negatives.
  • No allocation unlike the reverse-and-compare approach, which creates a new string.

Priya at the National Bank of India folds an account reference code in half and checks that the first character matches the last, the second matches the second-last, and so on. If every mirrored pair agrees, the code is a palindrome.

Understanding the Concepts

What does this question ask?

The interviewer wants you to check whether a string is a palindrome using the Stream API. This tests IntStream.range, allMatch with short-circuiting, and input normalization.

How do you check a palindrome with IntStream?

JAVA
package com.bank.core;

import java.util.stream.IntStream;

public class PalindromeCheck {
    public static boolean isPalindrome(String s) {
        int n = s.length();
        return IntStream.range(0, n / 2)
            .allMatch(i -> s.charAt(i) == s.charAt(n - 1 - i));
    }

    public static void main(String[] args) {
        String code1 = "ABCBA";
        String code2 = "SAV2001";

        System.out.println(code1 + " palindrome? " + isPalindrome(code1));
        System.out.println(code2 + " palindrome? " + isPalindrome(code2));
    }
}
TEXT
ABCBA palindrome? true
SAV2001 palindrome? false

Why do you only iterate half the string?

Once the first half matches the mirrored second half, the entire string is confirmed. A single middle character in an odd-length string mirrors itself and needs no check. Iterating the full string would compare each pair twice.

JAVA
// String: "ABCBA" (length 5)
// range(0, 2) generates indices 0 and 1
// i=0: 'A' == 'A' (index 4) -> match
// i=1: 'B' == 'B' (index 3) -> match
// Middle 'C' at index 2 mirrors itself -> no check needed
// Result: true

How does allMatch short-circuit?

allMatch stops processing the moment it finds a mismatch. For a string like "SAV2001", the first comparison fails because 'S' does not equal '1', so no further indices are checked.

JAVA
package com.bank.core;

import java.util.stream.IntStream;

public class ShortCircuitDemo {
    public static void main(String[] args) {
        String code = "SAV2001";
        int n = code.length();

        boolean result = IntStream.range(0, n / 2)
            .peek(i -> System.out.println(
                "Checking index " + i + ": '" + code.charAt(i)
                + "' vs '" + code.charAt(n - 1 - i) + "'"))
            .allMatch(i -> code.charAt(i) == code.charAt(n - 1 - i));

        System.out.println("Palindrome? " + result);
    }
}
TEXT
Checking index 0: 'S' vs '1'
Palindrome? false

Only one comparison ran before short-circuiting.

How do you normalize input for real-world checks?

Real palindrome checks ignore case, spaces, and punctuation.

JAVA
package com.bank.core;

import java.util.stream.IntStream;

public class NormalizedPalindrome {
    public static boolean isPalindrome(String input) {
        String cleaned = input.toLowerCase()
            .replaceAll("[^a-z0-9]", "");
        int n = cleaned.length();
        return IntStream.range(0, n / 2)
            .allMatch(i -> cleaned.charAt(i) == cleaned.charAt(n - 1 - i));
    }

    public static void main(String[] args) {
        System.out.println(isPalindrome("Was It A Car Or A Cat I Saw"));
        System.out.println(isPalindrome("A1B2B1A"));
        System.out.println(isPalindrome("SAV-2001"));
    }
}
TEXT
true
true
false

How is this different from reverse-and-compare?

| Approach | Allocations | Short-circuits | Time |
|---|---|---|---|
| IntStream allMatch | None | Yes, on first mismatch | O(n/2) worst case |
| Reverse and compare | New StringBuilder + String | No, always reverses full string | O(n) always |

JAVA
// Reverse-and-compare approach
boolean isPalindromeReverse(String s) {
    return s.equals(new StringBuilder(s).reverse().toString());
}
// Works but always processes the full string and allocates

The allMatch approach is more efficient because it stops at the first mismatch and allocates nothing.

What are the edge cases?

JAVA
package com.bank.core;

import java.util.stream.IntStream;

public class PalindromeEdgeCases {
    static boolean isPalindrome(String s) {
        int n = s.length();
        return IntStream.range(0, n / 2)
            .allMatch(i -> s.charAt(i) == s.charAt(n - 1 - i));
    }

    public static void main(String[] args) {
        System.out.println("Empty: " + isPalindrome(""));
        System.out.println("Single: " + isPalindrome("A"));
        System.out.println("Two same: " + isPalindrome("AA"));
        System.out.println("Two diff: " + isPalindrome("AB"));
    }
}
TEXT
Empty: true
Single: true
Two same: true
Two diff: false

Empty and single-character strings are palindromes by definition. The half-range range(0, 0) produces no indices, and allMatch on an empty stream returns true.

What are common mistakes?

Mistake: not normalizing case before checking.

JAVA
// WRONG: 'A' != 'a', so "Aba" fails
boolean wrong = isPalindrome("Aba");  // false!

// CORRECT: normalize first
String cleaned = "Aba".toLowerCase();
boolean correct = isPalindrome(cleaned);  // true

Mistake: using range(0, n) instead of range(0, n/2).

JAVA
// WRONG: checks every pair twice, wasting half the comparisons
IntStream.range(0, n)
    .allMatch(i -> s.charAt(i) == s.charAt(n - 1 - i));

// CORRECT: only the first half
IntStream.range(0, n / 2)
    .allMatch(i -> s.charAt(i) == s.charAt(n - 1 - i));

What are common interview follow-up questions?

  • "How do you find the longest palindromic substring?" Use dynamic programming or expand-around-center.
  • "How do you check if a number is a palindrome?" Convert to string and apply the same check, or reverse digits mathematically.
  • "Can you use this to validate account codes?" Yes, the bank can flag overly predictable palindromic reference codes as weak.

Visual Overview

DIAGRAM
  String: "ABCBA" (n = 5)

  IntStream.range(0, 2)  →  indices [0, 1]

  ┌─────────────────────────────────────┐
  │  Index 0: 'A' == 'A' (index 4)  YES│
  │  Index 1: 'B' == 'B' (index 3)  YES│
  │  Middle 'C' (index 2) → skip       │
  └─────────────────────────────────────┘
  allMatch → true → palindrome

  String: "SAV2001" (n = 7)
  ┌─────────────────────────────────────┐
  │  Index 0: 'S' == '1' (index 6)  NO │
  │  → short-circuit, return false      │
  └─────────────────────────────────────┘

Key Takeaway

To test whether a string is a palindrome with streams, take the length n and iterate only the first half using IntStream.range(0, n/2). For each index i, compare the character at i with its mirror at n-1-i, and wrap the comparison in allMatch. The method returns true only if every mirrored pair matches, and it short-circuits on the first mismatch.

Iterating only half the string is correct because once the first half matches the mirrored second half, the entire string is confirmed. A single middle character in an odd-length string mirrors itself and needs no check. This is more efficient than reversing the entire string and comparing, because it allocates nothing and stops early.

In real-world use at the National Bank of India, Rajesh normalizes the input first by lowercasing and stripping non-letter characters before the index comparison, so that mixed-case codes and punctuation are judged on their letters alone. The half-range approach also handles edge cases naturally: empty and single-character strings come out as palindromes, which is the correct behavior.

Remember one sentence: IntStream.range(0, n/2) with allMatch compares mirrored character pairs, short-circuits on the first mismatch, and allocates nothing.

---

Share
Use ← → arrow keys to navigate