LeetCodee

234. Palindrome Linked List

Jump to Solution: Python Java C++ JavaScript C#

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:

  1. Find the middle of the linked list:
    • Use slow and fast pointers technique
    • When fast reaches end, slow is at middle
  2. Reverse the second half of the list:
    • Start from the node after slow pointer
    • Use three pointers to reverse links
  3. 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