Given the head of a singly linked list, return true if the list reads the same forwards and backwards — a palindrome — and false otherwise.
A singly linked list only lets you walk forward: from any node you can reach node.next, but never the node before it. So the whole challenge is checking a back-to-front property using a structure that only moves front-to-back.
For example, 1 → 2 → 2 → 1 is a palindrome (the sequence [1,2,2,1] mirrors itself), while 1 → 2 is not.
true.next pointers before returning — still O(1) extra space.Input: head = [1,2,2,1] Output: true Reading the values forward gives [1,2,2,1]; backward gives [1,2,2,1] — identical.
Input: head = [1,2] Output: false Forward is [1,2], backward is [2,1] — they differ, so it is not a palindrome.
- The number of nodes in the list is in the range [1, 10^5]. - 0 <= Node.val <= 9
A palindrome check is trivial on an array — compare the two ends and walk inward. On a singly linked list you have no way to walk inward from the back, and that single restriction is the whole puzzle. We'll build up from the obvious copy-to-array approach to an elegant O(1)-space trick.
node.next; there is no pointer back to the previous node.next to the previous node reverses a list without extra memory.Restated plainly: collect the node values in order and ask whether that sequence equals its own reverse. Formally, with values v[0..n-1], the list is a palindrome iff v[i] == v[n-1-i] for every i.
Worked example — head = [1,2,3,2,1]
1 → 2 → 3 → 2 → 1
^ ^ v[0]=1, v[4]=1 ✓
^ ^ v[1]=2, v[3]=2 ✓
^ v[2]=3 (middle, ignored)
all mirrored pairs match → true
Stating what you'll confirm before coding shows you think about inputs, not just algorithms — exactly what an interviewer is grading.
“Is the list guaranteed to have at least one node?”
A single node is always a palindrome; an empty list is a vacuous edge case worth confirming.
“Can I mutate the list, or must its structure be preserved?”
The optimal approach reverses half the list; if the caller reuses it afterward you should restore it.
“How large can the list get?”
With up to 10^5 nodes, a quadratic compare is fine but the copy-to-array space may matter — it steers brute force vs the O(1) trick.
Before I start, I have a couple of quick clarifying questions.
First — can I assume at least one node, and how large can the list get?
And finally — am I allowed to modify the list in place, or should I leave it untouched when I'm done?
The first half compared front-to-back must match the second half compared back-to-front. The middle node (for odd length) never needs comparing — it mirrors itself.
Move slow by one and fast by two. When fast falls off the end, slow sits at the midpoint — no length count required.
1 → 2 → 3 → 2 → 1
s f
s f
s f=null → slow at 3 (middle)Once the back half points the other way, you have two forward-walkable chains — one from head, one from the new tail — and comparing them node-by-node needs no extra array.
| Copy to array | Reverse half in place | |
|---|---|---|
| Time | O(n) | O(n) |
| Space | O(n) | O(1) |
| Mutates list | Yes (restorable) |
Both run in linear time; the optimal one trades a little pointer juggling for constant extra space. See the full code for each in the Approaches selector below.
Key takeaway
When a structure only moves one way but you need a two-ended check, either materialize it (copy to an array) or make the far end walkable (reverse half in place). The slow/fast + reverse combo is the canonical O(1)-space pattern for linked-list symmetry.
slow, fast = head, head while fast and fast.next: slow = slow.next; fast = fast.next.next second = reverse(slow) while second: if head.val != second.val: return false; advance both return true