Taro Logo

Palindrome Linked List

Easy
Meta logo
Meta
0 views
Topics:
Linked ListsTwo Pointers

Given the head of a singly linked list, determine if it is a palindrome. A palindrome reads the same forwards and backward.

For example, the linked list [1, 2, 2, 1] is a palindrome, while [1, 2] is not.

Write a function that takes the head of a singly linked list as input and returns true if it is a palindrome and 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^5].
  • 0 <= Node.val <= 9

Follow up: Can you solve it in O(n) time and O(1) space?

Solution


Naive Solution: Convert to Array and Compare

One straightforward approach is to convert the linked list into an array and then check if the array is a palindrome. This is similar to checking if a string is a palindrome using two pointers from the start and end.

  1. Convert Linked List to Array: Iterate through the linked list and store the value of each node in an array.
  2. Palindrome Check: Use two pointers, one starting from the beginning and the other from the end of the array. Compare the values at these pointers and move them towards the center. If any values are not equal, the linked list is not a palindrome.

Code (Python):

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def isPalindrome(head):
    arr = []
    curr = head
    while curr:
        arr.append(curr.val)
        curr = curr.next
    
    left, right = 0, len(arr) - 1
    while left < right:
        if arr[left] != arr[right]:
            return False
        left += 1
        right -= 1
    return True

Time Complexity: O(n) to convert the linked list to an array and O(n) to check if the array is a palindrome, so the overall time complexity is O(n).

Space Complexity: O(n) to store the linked list elements in an array.

Optimal Solution: Reverse Second Half

To achieve O(1) space complexity, we can reverse the second half of the linked list and then compare the first half with the reversed second half.

  1. Find Middle: Use the fast and slow pointer technique to find the middle of the linked list.
  2. Reverse Second Half: Reverse the linked list starting from the middle.
  3. Compare Halves: Compare the first half of the original linked list with the reversed second half. If any values are not equal, the linked list is not a palindrome.
  4. Restore Original List: Reverse the second half again to restore the original linked list. (Optional, but good practice)

Code (Python):

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def isPalindrome(head):
    if not head or not head.next:
        return True

    # Find middle (slow pointer)
    slow = head
    fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next

    # Reverse the second half
    prev = None
    curr = slow
    while curr:
        next_node = curr.next
        curr.next = prev
        prev = curr
        curr = next_node

    # Compare first and second half
    first_half = head
    second_half = prev # prev is the head of reversed second half

    while second_half:
        if first_half.val != second_half.val:
            return False
        first_half = first_half.next
        second_half = second_half.next

    return True

Edge Cases:

  • Empty list: head == None. Returns True as an empty list is a palindrome.
  • Single element list: head.next == None. Returns True as a single element list is a palindrome.

Time Complexity:

  • O(n) to find the middle of the linked list.
  • O(n/2) to reverse the second half of the linked list, which simplifies to O(n).
  • O(n/2) to compare the two halves of the linked list, which simplifies to O(n).

Therefore, the overall time complexity is O(n).

Space Complexity: O(1) as we are only using a constant amount of extra space.