234. Palindrome Linked List
Problem Description
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
Constraints:
- The number of nodes in the list is in the range
[1, 10⁵] 0 <= Node.val <= 9
Follow up:
Could you do it in O(n) time and O(1) space?
Solution
Python Solution
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
if not head or not head.next:
return True
# Find middle using slow and fast pointers
slow = fast = head
while fast.next and fast.next.next:
slow = slow.next
fast = fast.next.next
# Reverse second half
second = slow.next
prev = None
while second:
next_temp = second.next
second.next = prev
prev = second
second = next_temp
# Compare first half with reversed second half
first = head
second = prev
while second:
if first.val != second.val:
return False
first = first.next
second = second.next
return True
Time Complexity: O(n)
We traverse the list three times: once to find the middle, once to reverse the second half, and once to compare.
Space Complexity: O(1)
Only uses a constant amount of extra space.
Java Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) {
return true;
}
// Find middle using slow and fast pointers
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// Reverse second half
ListNode second = slow.next;
ListNode prev = null;
while (second != null) {
ListNode nextTemp = second.next;
second.next = prev;
prev = second;
second = nextTemp;
}
// Compare first half with reversed second half
ListNode first = head;
second = prev;
while (second != null) {
if (first.val != second.val) {
return false;
}
first = first.next;
second = second.next;
}
return true;
}
}
Time Complexity: O(n)
We traverse the list three times: once to find the middle, once to reverse the second half, and once to compare.
Space Complexity: O(1)
Only uses a constant amount of extra space.
C++ Solution
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
bool isPalindrome(ListNode* head) {
if (!head || !head->next) {
return true;
}
// Find middle using slow and fast pointers
ListNode* slow = head;
ListNode* fast = head;
while (fast->next && fast->next->next) {
slow = slow->next;
fast = fast->next->next;
}
// Reverse second half
ListNode* second = slow->next;
ListNode* prev = nullptr;
while (second) {
ListNode* nextTemp = second->next;
second->next = prev;
prev = second;
second = nextTemp;
}
// Compare first half with reversed second half
ListNode* first = head;
second = prev;
while (second) {
if (first->val != second->val) {
return false;
}
first = first->next;
second = second->next;
}
return true;
}
};
Time Complexity: O(n)
We traverse the list three times: once to find the middle, once to reverse the second half, and once to compare.
Space Complexity: O(1)
Only uses a constant amount of extra space.
JavaScript Solution
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {boolean}
*/
var isPalindrome = function(head) {
if (!head || !head.next) {
return true;
}
// Find middle using slow and fast pointers
let slow = head;
let fast = head;
while (fast.next && fast.next.next) {
slow = slow.next;
fast = fast.next.next;
}
// Reverse second half
let second = slow.next;
let prev = null;
while (second) {
let nextTemp = second.next;
second.next = prev;
prev = second;
second = nextTemp;
}
// Compare first half with reversed second half
let first = head;
second = prev;
while (second) {
if (first.val !== second.val) {
return false;
}
first = first.next;
second = second.next;
}
return true;
};
Time Complexity: O(n)
We traverse the list three times: once to find the middle, once to reverse the second half, and once to compare.
Space Complexity: O(1)
Only uses a constant amount of extra space.
C# Solution
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int val=0, ListNode next=null) {
* this.val = val;
* this.next = next;
* }
* }
*/
public class Solution {
public bool IsPalindrome(ListNode head) {
if (head == null || head.next == null) {
return true;
}
// Find middle using slow and fast pointers
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// Reverse second half
ListNode second = slow.next;
ListNode prev = null;
while (second != null) {
ListNode nextTemp = second.next;
second.next = prev;
prev = second;
second = nextTemp;
}
// Compare first half with reversed second half
ListNode first = head;
second = prev;
while (second != null) {
if (first.val != second.val) {
return false;
}
first = first.next;
second = second.next;
}
return true;
}
}
Time Complexity: O(n)
We traverse the list three times: once to find the middle, once to reverse the second half, and once to compare.
Space Complexity: O(1)
Only uses a constant amount of extra space.
Approach Explanation
The solution uses a three-step approach to check if a linked list is a palindrome:
- Find the middle of the linked list:
- Use slow and fast pointers technique
- When fast reaches end, slow is at middle
- Reverse the second half of the list:
- Start from the node after slow pointer
- Use three pointers to reverse links
- Compare first half with reversed second half:
- Start from head and reversed second half
- Compare values node by node
Example walkthrough for [1,2,2,1]:
- Initial list: 1 → 2 → 2 → 1
- After finding middle: 1 → 2 | 2 → 1
- After reversing second half: 1 → 2 | 1 → 2
- Compare: (1,1) and (2,2) match ✓
Key insights:
- No extra space needed beyond pointers
- Original list structure is modified
- Works for both odd and even length lists
- Can be restored to original if needed