Given a singly linked list of integers. The task is to check if the given linked list is palindrome or not.
Examples:
Input: LinkedList: 1->2->1->1->2->1 Output: true Explanation: The given linked list is 1->2->1->1->2->1 , which is a palindrome and Hence, the output is true.![]()
Input: LinkedList: 1->2->3->4 Output: false Explanation: The given linked list is 1->2->3->4, which is not a palindrome and Hence, the output is false.
Expected Time Complexity: O(n)
Expected Auxiliary Space: O(1)
Note: You should not use the recursive stack space as well
Constraints:
1 <= number of nodes <= 105
1 ≤ node->data ≤ 103
Approach 01:
-
C++
-
Python
class Solution { public: // Function to check whether the list is palindrome. bool isPalindrome(Node* head) { Node* slowPointer = head; Node* fastPointer = head; Node* previousPointer = nullptr; // Finding the middle of the linked list using two-pointer technique while (fastPointer && fastPointer->next) { previousPointer = slowPointer; slowPointer = slowPointer->next; fastPointer = fastPointer->next->next; } // Detaching the first half of the list if (previousPointer) previousPointer->next = nullptr; previousPointer = nullptr; // Reversing the second half of the linked list while (slowPointer) { Node* nextNode = slowPointer->next; slowPointer->next = previousPointer; previousPointer = slowPointer; slowPointer = nextNode; } // Comparing both halves while (head) { if (head->data != previousPointer->data) return false; head = head->next; previousPointer = previousPointer->next; } return true; } };
class Solution: def isPalindrome(self, head): slowPointer = head fastPointer = head previousPointer = None # Finding the middle of the linked list using two-pointer technique while fastPointer and fastPointer.next: previousPointer = slowPointer slowPointer = slowPointer.next fastPointer = fastPointer.next.next # Detaching the first half of the list if previousPointer: previousPointer.next = None previousPointer = None # Reversing the second half of the linked list while slowPointer: nextNode = slowPointer.next slowPointer.next = previousPointer previousPointer = slowPointer slowPointer = nextNode # Comparing both halves while head: if head.data != previousPointer.data: return False head = head.next previousPointer = previousPointer.next return True
Time Complexity
- Finding the middle of the linked list:
We use the slow and fast pointer technique to find the middle of the list. In each iteration, the slow pointer moves one step, and the fast pointer moves two steps. This step takes \(O(n / 2)\) time, where \(n\) is the number of nodes in the linked list.
- Reversing the second half of the list:
Once we find the middle, we reverse the second half of the linked list. This operation iterates over the second half, which takes \(O(n / 2)\) time.
- Comparing the two halves:
After reversing the second half, we compare it with the first half. This comparison takes \(O(n / 2)\) time.
- Overall Time Complexity:
The operations (finding the middle, reversing, and comparing) are all linear in terms of the size of the list. Therefore, the total time complexity is \(O(n)\), where \(n\) is the length of the linked list.
Space Complexity
- Reversing the second half:
We reverse the second half of the list in place, so no extra space is used for storing nodes.
- Pointer Variables:
We use a constant amount of extra space for the pointers (
slowPointer
,fastPointer
,previousPointer
, andnextNode
). These are all single variables, so the space complexity is constant \(O(1)\). - Overall Space Complexity:
The overall space complexity is \(O(1)\), as we are not using any extra space except for the pointer variables.