Palindrome Linked List
Check linked-list palindromicity by reversing the second half in place and walking both halves.
4 min read
fast-slow linked-list
Problem#
Return true if the singly linked list reads the same forward and backward.
Examples#
[1,2,2,1]→true[1,2]→false
Constraints#
- Length in
[1, 10^5].
Approach#
- Find the middle with fast/slow.
- Reverse the second half in place.
- Walk first half and reversed second half; if they match throughout, palindrome.
Solution#
class Solution {public: bool isPalindrome(ListNode* head) { ListNode *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } // Reverse from slow to end. ListNode* prev = nullptr; while (slow) { ListNode* nxt = slow->next; slow->next = prev; prev = slow; slow = nxt; } // Compare halves. ListNode *a = head, *b = prev; while (b) { if (a->val != b->val) return false; a = a->next; b = b->next; } return true; }};func isPalindrome(head *ListNode) bool { slow, fast := head, head for fast != nil && fast.Next != nil { slow = slow.Next fast = fast.Next.Next } // Reverse from slow to end. var prev *ListNode for slow != nil { nxt := slow.Next slow.Next = prev prev = slow slow = nxt } // Compare halves. a, b := head, prev for b != nil { if a.Val != b.Val { return false } a = a.Next b = b.Next } return true}from typing import Optional
class Solution: def isPalindrome(self, head: Optional[ListNode]) -> bool: slow, fast = head, head while fast is not None and fast.next is not None: slow = slow.next fast = fast.next.next # Reverse from slow to end. prev = None while slow is not None: nxt = slow.next slow.next = prev prev = slow slow = nxt # Compare halves. a, b = head, prev while b is not None: if a.val != b.val: return False a = a.next b = b.next return Truefunction isPalindrome(head) { let slow = head, fast = head; while (fast !== null && fast.next !== null) { slow = slow.next; fast = fast.next.next; } // Reverse from slow to end. let prev = null; while (slow !== null) { const nxt = slow.next; slow.next = prev; prev = slow; slow = nxt; } // Compare halves. let a = head, b = prev; while (b !== null) { if (a.val !== b.val) return false; a = a.next; b = b.next; } return true;}class Solution { public boolean isPalindrome(ListNode head) { ListNode slow = head, fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } // Reverse from slow to end. ListNode prev = null; while (slow != null) { ListNode nxt = slow.next; slow.next = prev; prev = slow; slow = nxt; } // Compare halves. ListNode a = head, b = prev; while (b != null) { if (a.val != b.val) return false; a = a.next; b = b.next; } return true; }}function isPalindrome(head: ListNode | null): boolean { let slow: ListNode | null = head, fast: ListNode | null = head; while (fast !== null && fast.next !== null) { slow = slow!.next; fast = fast.next.next; } // Reverse from slow to end. let prev: ListNode | null = null; while (slow !== null) { const nxt: ListNode | null = slow.next; slow.next = prev; prev = slow; slow = nxt; } // Compare halves. let a: ListNode | null = head, b: ListNode | null = prev; while (b !== null) { if (a!.val !== b.val) return false; a = a!.next; b = b.next; } return true;}Editorial#
The middle-then-reverse approach gives O(1) space. Comparing until the shorter (reversed second) half is exhausted handles odd lengths automatically: the middle element pairs with itself trivially. Optionally restore the list by reversing the second half again before returning.
Complexity#
- Time: O(n).
- Space: O(1).
Concept revision#
Related#