Back to DSA & Algorithms
DSA & Algorithms
easy
mid

How would you check if a string is a palindrome without reversing it?

Use the two-pointer technique: one pointer from each end moving inward, comparing characters. O(n) time, O(1) space — no reversal, no extra allocation. Clarify whether to normalize case/whitespace/punctuation first.

4 min read·~10 min to think through

The constraint "without reversing" is pushing you toward the two-pointer technique — which is actually the better solution anyway (no extra allocation).

Two-pointer approach

js
function isPalindrome(str) {
  let left = 0;
  let right = str.length - 1;
  while (left < right) {
    if (str[left] !== str[right]) return false;
    left++;
    right--;
  }
  return true;
}
  • Compare the outermost pair, move inward. First mismatch → not a palindrome.
  • Loop ends when the pointers meet (odd length: middle char ignored, correctly).
  • O(n) time (really n/2 comparisons), O(1) space — beats the reverse-and-compare approach which allocates a whole new string.

Clarify the requirements first

Always ask: "raw characters, or normalized?" Common variant — ignore case, spaces, and punctuation ("A man, a plan, a canal: Panama"):

js
function isPalindrome(str) {
  const s = str.toLowerCase().replace(/[^a-z0-9]/g, "");
  let left = 0, right = s.length - 1;
  while (left < right) {
    if (s[left++] !== s[right--]) return false;
  }
  return true;
}

Recursive variant (if they ask)

js
const isPal = (s, l = 0, r = s.length - 1) =>
  l >= r ? true : s[l] !== s[r] ? false : isPal(s, l + 1, r - 1);

Same O(n) time but O(n) call stack — worse than the loop for large inputs.

Edge cases

  • Empty string / single char → true (vacuously a palindrome).
  • Unicode — str[i] indexes UTF-16 code units, so emoji/surrogate pairs break it; use [...str] to split into code points if Unicode matters.
  • Whitespace/case — depends entirely on the spec; ask.

What interviewers want

Reach for two pointers immediately, state O(n)/O(1), and ask the normalization question before coding — that clarification is itself a signal.

Follow-up questions

  • Why is two-pointer better than reverse-and-compare?
  • How would you handle the 'ignore punctuation and case' variant?
  • What's the tradeoff of the recursive version?
  • How does this break on emoji / Unicode, and how do you fix it?

Common mistakes

  • Reversing the string anyway (the prompt explicitly forbids it) — and allocating extra memory.
  • Not clarifying whether to normalize case/whitespace/punctuation.
  • Off-by-one in the pointer loop condition.
  • Indexing with [i] and breaking on surrogate pairs.

Performance considerations

  • Two-pointer is O(n) time, O(1) space — strictly better than building a reversed string (O(n) extra space). Recursion is O(n) time but O(n) stack.

Edge cases

  • Empty string and single character → true.
  • Mixed case / punctuation when normalization is expected.
  • Unicode characters and emoji.
  • Strings with only whitespace.

Real-world examples

  • Input validation, simple string-symmetry checks, a warm-up before harder palindrome problems (longest palindromic substring).

Senior engineer discussion

Seniors go straight to two pointers, state O(n)/O(1), and proactively ask the normalization question before writing code. They mention the Unicode indexing pitfall and note that the recursive form trades O(1) space for O(n) stack.

Related questions