Reference: LeetCode
Difficulty: EasyTwo Pointers
My Post: Java Solution Using Two Pointers, Half Reverse (easy-understand)
Problem
Given a singly linked list, determine if it is a palindrome.
Example:
1 | Input: 1->2 |
Follow up: Could you do it in $O(n)$ time and $O(1)$ space?
Analysis
Reverse Whole
Reverse the whole list and compare each element, but reversal should be non-destructive because we need to do comparison later.
Note: Non-destructive reversing can be tricky at the first glance.
1 | public boolean isPalindrome(ListNode head) { |
Time: $O(N)$
Space: $O(N)$
Reverse Half
The idea is to reverse the right half of the original list and then compare half elements. The difficulties lie in:
- Handle even and odd cases.
- How to get the right half.
1 | // even |
To get the right half, we have two ways: Traversal based on the length, Slow-fast pointers. Here we use the slow-fast pointers to find the middle point.
In the examples above, which nodes do we want as heads of the right half? 3 (even case) and 4 (odd case).
So we can find the left-leaning middle point 2 and the exact middle point 3 by slow-fast pointers. Finally, returns their the next node.
In terms of left-leaning and right-leaning, check out the code and examples to get an intuition.
1 | private ListNode getRightHalf(ListNode head) { |
In the code, the difference is in the initializations of fast.
1 | // left-leaning |
By observation, we want to use left-leaning in this case because slow could finally stop at the left-leaning middle point.
Here is the code:
1 | public boolean isPalindrome(ListNode head) { |
Note: We use p2 instead of p1 as our while-condition because p1 actually points to the list of all elements (reverse and getRightHalf do not disconnect the list). For example:
1 | Example: 1 -> 2 -> 3 -> 4 -> 5 |
The remaining helper function reverse():
1 | // iteration |
Time: $O(N)$
Space: $O(1)$ if not using recursion.