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:
[1, 105]
.0 <= Node.val <= 9
Follow up: Could you do it in
O(n)
time and O(1)
space?This problem asks to determine if a singly linked list is a palindrome. The most efficient solution uses a two-pointer approach and reverses the second half of the list. This allows for an O(n) time complexity solution with O(1) space complexity.
Algorithm:
Find the middle: Use two pointers, slow
and fast
. slow
moves one step at a time, while fast
moves two steps at a time. When fast
reaches the end, slow
will be at the middle of the linked list.
Reverse the second half: Reverse the linked list starting from slow.next
. This is done iteratively to avoid stack overflow issues in recursive solutions.
Compare: Compare the first half and the reversed second half of the list. If they are the same, the list is a palindrome; otherwise, it's not.
Time Complexity: O(n), where n is the number of nodes in the linked list. We traverse the list once to find the middle and once to reverse the second half. Comparing the two halves takes O(n/2) which is still O(n).
Space Complexity: O(1). We only use a few pointers, so the space used is constant regardless of the input size.
Code Explanation (Python as an example):
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
# Find the middle of the linked list
slow, fast = head, head.next
while fast and fast.next:
slow, fast = slow.next, fast.next.next
# Reverse the second half of the linked list
pre, cur = None, slow.next
while cur:
t = cur.next
cur.next = pre
pre, cur = cur, t
# Compare the first and reversed second halves
while pre:
if pre.val != head.val:
return False
pre, head = pre.next, head.next
return True
slow
, fast
Initialization: We initialize two pointers, slow
and fast
, to traverse the linked list.
Finding the Middle: The while
loop iterates until fast
reaches the end (or one node before the end for odd length lists). This ensures slow
points to the middle node.
Reversing the Second Half: The next loop reverses the portion of the linked list starting from slow.next
. It uses three pointers: pre
(previous node), cur
(current node), and t
(temporary node to store the next node).
Comparison: The final loop compares the values of nodes in the first half and the reversed second half. If any pair doesn't match, it returns False
. Otherwise, it returns True
.
The provided code in other languages follows the same logic, only differing in syntax. The core algorithm remains consistent across all implementations.