Palindrome Strings: Check and Solve

Learn Palindrome Strings: Check and Solve with practical examples, explanations, best practices, and real-world coding techniques.

What Is a Palindrome String?

A palindrome is a sequence that reads the same forward and backward. A palindrome string therefore has the same character order when viewed from either direction.

"level"  → palindrome
"radar"  → palindrome
"hello"  → not a palindrome

Palindrome problems are useful for learning string traversal, character comparison, two-pointer techniques, and the practical use of data structures. They are also common coding interview exercises because the basic problem can be extended with additional rules such as ignoring spaces, punctuation, or letter casing.

How to Recognize a Palindrome

A string is a palindrome when the first character matches the last, the second character matches the second-to-last, and so on until the middle of the string is reached.

String:  R A C E C A R
         ↑           ↑
        first       last

R = R

        ↑       ↑
       A         A

A = A

            ↑ ↑
            C C

C = C

Result: palindrome

This observation leads directly to the two-pointer approach, which compares characters from both ends and moves toward the center.

Palindrome Check with Two Pointers

The two-pointer technique is one of the most efficient and commonly taught approaches. One pointer starts at the beginning of the string and another starts at the end. If the characters differ, the string cannot be a palindrome.

function isPalindrome(text) {
  let left = 0;
  let right = text.length - 1;

  while (left < right) {
    if (text[left] !== text[right]) {
      return false;
    }

    left++;
    right--;
  }

  return true;
}

console.log(isPalindrome("level"));
// true

console.log(isPalindrome("hello"));
// false

How the Two-Pointer Method Works

Consider the word "level". The pointers initially point to the first and last characters.

l e v e l
↑       ↑
L       R

l === l
  ↑   ↑
  L   R

e === e
    ↑
    M

Once the pointers meet or cross, every required pair has matched, so the string is a palindrome.

Why Only Half the String Needs to Be Checked

Every comparison checks two characters at the same time. Once the pointers reach the middle, all mirrored pairs have already been verified. There is no need to compare the second half independently.

For a string of length n, the algorithm performs at most about n / 2 comparisons. In Big O notation, this is still O(n) time.

Palindrome Check Using String Reversal

Another simple approach is to reverse the string and compare the result with the original string. If both strings are identical, the input is a palindrome.

function isPalindrome(text) {
  const reversed = text.split("").reverse().join("");

  return text === reversed;
}

console.log(isPalindrome("racecar"));
// true

console.log(isPalindrome("developer"));
// false

This approach is concise and easy to understand. However, it creates an additional array and reversed string, so it uses more auxiliary memory than a direct comparison with two pointers.

Ignoring Letter Case

Some palindrome problems treat uppercase and lowercase letters as equivalent. In that case, normalize the input before performing the comparison.

function isPalindrome(text) {
  text = text.toLowerCase();

  let left = 0;
  let right = text.length - 1;

  while (left < right) {
    if (text[left] !== text[right]) {
      return false;
    }

    left++;
    right--;
  }

  return true;
}

console.log(isPalindrome("Level"));
// true

Whether case should be ignored is a requirement of the specific problem. It should not be assumed unless the input rules call for it.

Ignoring Spaces and Punctuation

A common variation asks whether a sentence is a palindrome while ignoring spaces, punctuation, and letter casing. For example, a phrase may be considered a palindrome after keeping only alphanumeric characters.

function isPalindromePhrase(text) {
  const normalized = text
    .toLowerCase()
    .replace(/[^a-z0-9]/g, "");

  let left = 0;
  let right = normalized.length - 1;

  while (left < right) {
    if (normalized[left] !== normalized[right]) {
      return false;
    }

    left++;
    right--;
  }

  return true;
}

console.log(
  isPalindromePhrase("A man, a plan, a canal: Panama")
);
// true

The normalization step changes the problem slightly. Instead of checking the original string directly, the algorithm checks a cleaned representation containing only the characters relevant to the comparison.

Two Pointers Without Creating a New String

If memory usage matters, the input can be examined directly while skipping characters that should not participate in the palindrome comparison. This avoids creating a complete normalized copy.

function isPalindromePhrase(text) {
  let left = 0;
  let right = text.length - 1;

  while (left < right) {
    while (
      left < right &&
      !/[a-z0-9]/i.test(text[left])
    ) {
      left++;
    }

    while (
      left < right &&
      !/[a-z0-9]/i.test(text[right])
    ) {
      right--;
    }

    if (
      text[left].toLowerCase() !==
      text[right].toLowerCase()
    ) {
      return false;
    }

    left++;
    right--;
  }

  return true;
}

console.log(
  isPalindromePhrase("A man, a plan, a canal: Panama")
);
// true

Palindrome Using a Stack

A stack can also be used to check whether a string is a palindrome. Because a stack returns elements in reverse order, pushing all characters and then popping them allows the reversed sequence to be compared with the original sequence.

function isPalindrome(text) {
  const stack = [];

  for (const char of text) {
    stack.push(char);
  }

  for (const char of text) {
    if (char !== stack.pop()) {
      return false;
    }
  }

  return true;
}

console.log(isPalindrome("level"));
// true

console.log(isPalindrome("hello"));
// false

This approach demonstrates the relationship between palindrome problems and the LIFO behavior of stacks. It is useful for learning data structures, although the two-pointer method generally requires less additional memory for this specific problem.

Palindrome with Recursion

A palindrome can also be checked recursively by comparing the first and last characters, then recursively checking the substring between them.

function isPalindrome(text, left = 0, right = text.length - 1) {
  if (left >= right) {
    return true;
  }

  if (text[left] !== text[right]) {
    return false;
  }

  return isPalindrome(text, left + 1, right - 1);
}

console.log(isPalindrome("racecar"));
// true

The recursive solution mirrors the definition of a palindrome, but it uses the JavaScript call stack for recursive calls. An iterative two-pointer solution is generally easier to control for very large inputs.

Handling Empty and Single-Character Strings

An empty string and a single-character string are both palindromes because there is no pair of characters that violates the palindrome condition.

console.log(isPalindrome(""));
// true

console.log(isPalindrome("a"));
// true

console.log(isPalindrome("aa"));
// true

console.log(isPalindrome("ab"));
// false

The two-pointer loop naturally handles these cases because the pointers either start at the same position or meet without finding a mismatch.

Palindrome Numbers as a Related Problem

The same mirrored-comparison idea can be applied to numbers. A number such as 121 reads the same in both directions. One approach is to convert the number to a string, while another reverses the digits mathematically.

function isPalindromeNumber(number) {
  const text = String(number);

  return text === text.split("").reverse().join("");
}

console.log(isPalindromeNumber(121));
// true

console.log(isPalindromeNumber(123));
// false

Number-palindrome problems may have additional requirements, such as avoiding string conversion. In those cases, the algorithm needs to work directly with the digits.

Comparing Palindrome Approaches

Approach Time Extra Space Useful For
Two pointers O(n) O(1) auxiliary space Efficient palindrome checks
Reverse and compare O(n) O(n) Simple implementations
Stack O(n) O(n) Learning LIFO-based solutions
Recursion O(n) O(n) call stack Understanding recursive logic

A Useful Interview Pattern

When a problem asks whether two ends of a sequence have matching values, consider whether a two-pointer approach can reduce unnecessary work. For palindrome strings, the comparison naturally moves inward from both boundaries.

left →              ← right

[a][b][c][d][c][b][a]

Compare:
a with a
b with b
c with c

Stop at the middle.

This pattern is useful beyond strings. Similar left-and-right comparisons appear in sorted arrays, pair-search problems, partitioning algorithms, and other sequence-based challenges.

Common Mistakes

  • Comparing every character with every other character and creating unnecessary O(n²) work.
  • Forgetting to move both pointers after a successful comparison.
  • Using the wrong normalization rules for spaces, punctuation, or case.
  • Treating an empty or single-character string as invalid without checking the problem requirements.
  • Creating a reversed string when the problem specifically requires constant auxiliary space.

Complexity Analysis

For a string containing n characters, the two-pointer solution performs at most approximately n / 2 comparisons. Therefore, its time complexity is O(n), while its auxiliary space is O(1) when the original input can be accessed directly.

Approaches that create a reversed string, normalized copy, or stack require additional memory proportional to the input size.

Key Takeaways

  • A palindrome reads the same from left to right and right to left.
  • The two-pointer technique compares mirrored characters efficiently.
  • A direct two-pointer check runs in O(n) time with O(1) auxiliary space.
  • Reversing and comparing is simple but requires additional memory.
  • A stack can demonstrate how LIFO ordering helps solve palindrome problems.
  • Case, spaces, and punctuation should be handled according to the problem requirements.
  • Empty and single-character strings are normally palindromes.

Code Examples

function isPalindrome(text) {
  let left = 0;
  let right = text.length - 1;

  while (left < right) {
    if (text[left] !== text[right]) {
      return false;
    }

    left++;
    right--;
  }

  return true;
}

console.log(isPalindrome("racecar"));
// true

console.log(isPalindrome("developer"));
// false
    
function isPalindrome(text) {
  const normalized = text
    .toLowerCase()
    .replace(/[^a-z0-9]/g, "");

  let left = 0;
  let right = normalized.length - 1;

  while (left < right) {
    if (normalized[left] !== normalized[right]) {
      return false;
    }

    left++;
    right--;
  }

  return true;
}

console.log(
  isPalindrome("A man, a plan, a canal: Panama")
);
// true
    
function isPalindrome(text) {
  const stack = [];

  for (const char of text) {
    stack.push(char);
  }

  for (const char of text) {
    if (char !== stack.pop()) {
      return false;
    }
  }

  return true;
}

console.log(isPalindrome("level"));
// true

console.log(isPalindrome("hello"));
// false
    

Pro Tip

For palindrome interview problems, start with two pointers at the beginning and end of the string. Compare mirrored characters and move inward; this usually gives an O(n) solution with O(1) auxiliary space.

🎨 IgKnight Docs

Master HTML, CSS, JS, Python, .NET and more with easy-to-follow lessons and practical code examples.

© 2025 IgKnight Learning Platform. All rights reserved.