Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Palindrome Checker

The Problem

Given a string, determine whether it is a palindrome — a word or phrase that reads the same forwards and backwards.

Input:  s = "racecar"   →   Output: True
Input:  s = "hello"     →   Output: False

Examples

Example 1

Input:  "racecar"
Output: True
Explanation: r-a-c-e-c-a-r reversed is still r-a-c-e-c-a-r

Example 2

Input:  "hello"
Output: False
Explanation: 'h' ≠ 'o' — the first and last characters already disagree

Example 3

Input:  "abcba"
Output: True

Example 4 — single character

Input:  "a"
Output: True   (every single character is trivially a palindrome)

Intuition

A string is a palindrome when its first character equals its last, its second equals its second-to-last, and so on all the way to the middle.

That’s a mirror-pair relationship — exactly what two pointers are built for. Place left at the start and right at the end. At each step, compare s[left] and s[right]:

  • If they match → the pair is fine, move both inward and continue
  • If they don’t match → it’s not a palindrome, return False immediately
  • If left >= right without any mismatch → every pair matched, return True

No extra memory needed. One pass.

---
config:
  theme: base
  themeVariables:
    primaryColor: "#dbeafe"
    primaryBorderColor: "#3b82f6"
    primaryTextColor: "#1e3a5f"
    lineColor: "#64748b"
    secondaryColor: "#ede9fe"
    tertiaryColor: "#fef9c3"
---
flowchart TB
  subgraph S0["Start  —  left=0, right=6"]
    direction LR
    P0L(["left"]) --> R0["r"] --- A0["a"] --- C0["c"] --- E0["e"] --- C1["c"] --- A1["a"] --- R1["r"]
    R1 --> P0R(["right"])
  end
  subgraph S1["'r'='r' ✓  left=1, right=5"]
    direction LR
    P1L(["left"]) --> A2["a"] --- C2["c"] --- E1["e"] --- C3["c"] --- A3["a"]
    A3 --> P1R(["right"])
  end
  subgraph S2["'a'='a' ✓  left=2, right=4"]
    direction LR
    P2L(["left"]) --> C4["c"] --- E2["e"] --- C5["c"]
    C5 --> P2R(["right"])
  end
  subgraph S3["'c'='c' ✓  left=3, right=3"]
    direction LR
    P3L(["left=right"]) --> E3["e"]
    E3 --> P3R(["right=left"])
  end
  subgraph S4["left ≥ right  →  all pairs matched"]
    DONE(["✓  return True"])
  end

  S0 -->|"match → move inward"| S1
  S1 -->|"match → move inward"| S2
  S2 -->|"match → move inward"| S3
  S3 -->|"left ≥ right"| S4

Checking "racecar" for palindrome — every mirror pair matches; when pointers meet at the centre, the check passes.


Applying the Diagnostic Questions

CheckAnswer for Palindrome Checker
✅ Two positions simultaneously?Yes — s[left] and s[right] are compared together at every step
✅ One near start, one near end?Yes — left = 0, right = n-1
✅ Both move inward?Yes — left++, right-- after every matching pair
✅ Simple work at each step?Yes — one comparison per iteration, return immediately on mismatch

The structure is identical to Flip Characters — the only difference is the loop body: compare instead of swap.

Why check from both ends simultaneously? A palindrome’s definition is symmetric: the character at position i from the left must equal the character at position i from the right, for every i from 0 to n/2. Two pointers map this requirement directly — left and right track the pair at distance i from each end. Moving both inward covers every required pair in exactly n/2 steps.

What breaks if you use only one pointer? A single pointer could reverse the string and compare — but that costs O(n) extra space for the reversed copy and a second O(n) pass. Two pointers do it in one pass with O(1) space, and gain the early-exit advantage: as soon as any pair mismatches, False is returned without inspecting the rest. For a string like "abcde...xyz" + "XYZ", the mismatch at position 0 stops the algorithm immediately.


What Failure Looks Like

---
config:
  theme: base
  themeVariables:
    primaryColor: "#dbeafe"
    primaryBorderColor: "#3b82f6"
    primaryTextColor: "#1e3a5f"
    lineColor: "#64748b"
    secondaryColor: "#ede9fe"
    tertiaryColor: "#fef9c3"
---
flowchart LR
  subgraph FAIL["Checking 'hello'  —  left=0, right=4"]
    direction LR
    FL(["left"]) --> H["h"] --- E["e"] --- L1["l"] --- L2["l"] --- O["o"]
    O --> FR(["right"])
  end
  CMP{"'h' = 'o' ?"}
  NO(["✗  return False"])

  FAIL --> CMP
  CMP -->|"No"| NO

The check fails immediately on the first pair — 'h' ≠ 'o' is enough to return False without looking at the rest.

This early-exit property makes two-pointer palindrome checking efficient in practice — you never process more pairs than necessary.


Solution

class Solution:
    def is_palindrome(self, s: str) -> bool:
        left  = 0
        right = len(s) - 1

        while left < right:
            if s[left] != s[right]:
                return False   # mismatch found — not a palindrome

            left  += 1
            right -= 1

        return True   # all mirror pairs matched


# --- Test ---
sol = Solution()
print(sol.is_palindrome("racecar"))  # True
print(sol.is_palindrome("hello"))    # False
print(sol.is_palindrome("abcba"))    # True
print(sol.is_palindrome("a"))        # True
print(sol.is_palindrome("ab"))       # False
print(sol.is_palindrome("aa"))       # True

Dry Run — “racecar”

s = "racecar", n = 7

Iterationleftrights[left]s[right]Match?
106'r''r'
215'a''a'
324'c''c'
33left ≥ right → stop

Return True


Dry Run — “hello”

Iterationleftrights[left]s[right]Match?
104'h''o'❌ → return False immediately

Return False


Complexity Analysis

ComplexityReasoning
TimeO(n) worst caseEvery mirror pair checked once if all match; exits early on first mismatch
SpaceO(1)Only two pointer variables

Edge Cases

ScenarioInputOutputNote
Empty string""Trueleft = 0 > right = -1 — loop never runs, vacuously true
Single character"a"Trueleft = right — loop never runs
Two identical chars"aa"TrueOne comparison, both match
Two different chars"ab"FalseOne comparison, immediate mismatch
All same characters"aaaa"TrueEvery pair matches

Key Takeaway

Palindrome checking is the comparison variant of the two-pointer pattern. Where “Flip Characters” swapped mirror pairs, here we compare them. The pointer movement is identical — the work in the loop body is the only difference. This is the pattern: same skeleton, swap the operation.