234 - Palindrome Linked List
Difficulty: Easy | Pattern: Two Pointers + Reverse | Company tags: Amazon, Facebook, Apple, Google
Problem Statement
Given the head of a singly linked list, return true if it is a palindrome or false otherwise.
Example 1:
Input: head = [1,2,2,1]
Output: true
Example 2:
Input: head = [1,2]
Output: false
Follow-up: Can you do it in O(n) time and O(1) space?
Approach: Find Middle + Reverse Second Half — O(n), O(1)
Key insight:
- Find the middle of the list (slow/fast pointers)
- Reverse the second half
- Compare first half with reversed second half
def isPalindrome(head) -> bool:
# Step 1: Find middle
slow = fast = head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# Step 2: Reverse second half
prev = None
curr = slow
while curr:
curr.next, prev, curr = prev, curr, curr.next
# Step 3: Compare
left, right = head, prev
while right: # right is the reversed second half
if left.val != right.val:
return False
left = left.next
right = right.next
return True
Algorithm Flow
Dry Run
head = [1,2,2,1]
Step 1 (find middle): slow=2(index 2), fast=1(end) Step 2 (reverse [2,1]): prev=1→2→None → reversed: 1→2 Step 3 (compare [1,2,2,1] with [1,2]):
- left=1, right=1: 1==1 ✓
- left=2, right=2: 2==2 ✓
- right=None → stop
Return True ✓
Simpler Approach: Copy to Array — O(n), O(n)
def isPalindrome(head) -> bool:
vals = []
while head:
vals.append(head.val)
head = head.next
return vals == vals[::-1]
Edge Cases
- Single node → True
- Two nodes: equal → True, different → False
- Odd length: middle node is not compared (it matches itself)
Complexity
| Approach | Time | Space |
|---|---|---|
| Reverse half | O(n) | O(1) |
| Copy to array | O(n) | O(n) |
Key Terms
| Term | Definition in this problem's context |
|---|---|
| Slow/fast pointers | Slow moves one node at a time, fast moves two; when fast reaches the end, slow sits at the middle of the list. |
| In-place reversal | Reversing the second half by rewiring .next pointers instead of copying values, keeping space O(1). |
| Two-pointer comparison | After reversal, walking the original first half and the reversed second half together to compare values. |
| Mutation side-effect | Reversing the second half destroys the original list structure; a real interview answer should mention restoring it if required. |
FAQ
-
Can this be solved without extra space? Yes — the find-middle + reverse-second-half approach uses O(1) extra space by reversing pointers in place, versus the O(n) array-copy approach.
-
What happens with an odd-length list? The slow pointer lands on the middle node, which becomes the head of the reversed second half; it's compared against itself implicitly since the comparison loop only runs
right(the shorter or equal-length reversed half), so the middle element is naturally skipped from mismatch checks without special-casing. -
Does the in-place approach mutate the input list? Yes — reversing the second half changes the list's structure permanently unless you re-reverse it back after comparison, which interviewers may ask you to add for restoring the original list.
-
What if the list is empty or has one node? An empty list is trivially a palindrome (loop never executes, returns True); a single node has
fast=head,fast.next=Noneimmediately, so slow never advances, and reversing/comparing one node against itself returns True. -
What's a common follow-up interviewers ask? "Can you restore the list to its original order after checking?" — requires re-reversing the second half once comparison is done, still keeping O(1) space.
Quick Revision
- Pattern: slow/fast pointers to find middle, then in-place reversal, then two-pointer comparison.
- Slow pointer advances 1 step, fast advances 2 steps — when fast hits the end, slow is at (or just past) the middle.
- Reverse the list starting from
slowusing the standard three-pointer (prev,curr,next) reversal. - Compare
head(first half) against the reversed second half node by node. - Stop comparison when the reversed half (
right) is exhausted — this naturally skips the middle node in odd-length lists. - Optimal solution: O(n) time, O(1) space.
- Simpler alternative: copy values into an array and check
arr == arr[::-1]— O(n) time, O(n) space. - Edge cases: empty list and single node both trivially return True.
- Trade-off to mention in interviews: in-place reversal mutates the list unless restored afterward.
Related Problems
- 206-ReverseLinkedList — the exact reversal subroutine used on the second half here.
- 876-MiddleOfTheLinkedList — the slow/fast pointer technique used to find the split point.
- 142-LinkedListCycleII — shares the slow/fast pointer pattern for a different structural property (cycle detection).