Palindrome Linked List
Determining if a singly linked list is a palindrome involves checking whether the elements in the first half of the list are the same as those in the second half but in reverse order.
Here’s a simple approach to check if a linked list is a palindrome:
Find the Middle of the List: You can do this using the slow and fast pointer technique, where the slow pointer advances one step, and the fast pointer advances two steps. When the fast pointer reaches the end of the list, the slow pointer will be at the middle.
Reverse the Second Half: From the middle of the list, reverse the second half of the linked list.
Compare the First and Second Halves: Compare the elements of the first half of the list with the reversed second half. If they are the same, the linked list is a palindrome.
Restore the Original List Structure (Optional): If you want to keep the original structure of the list, you should reverse the second half again.
Here’s the code:
|
|
This code first finds the middle of the linked list, reverses the second half, and then compares both halves to check if the linked list is a palindrome. It returns True
if the linked list is a palindrome, False
otherwise.
Define the Terms
palindrome : Reads the same forward and backwards Instead of string, we have numbers 1-2 1-2-2-1
Define the Interface Input: Head of the linked list Output: boolean (palindrome or not)
Analyze the Input and Output
Identify the Invariants
Identify the constraints
- T: O(N)
- S: O(1)
Search the Problem Space
Classify the Problem
Analyze the Examples
Solve the Problem by Hand
Describe the Pattern
Distill the Observations to Create Insights
Brute Force Approach Recursive approach becomes messy in this case. Going backward is problematic (not doubly linked list)
Wishful Thinking and Working Backwards Tower of Hanoi
Imagine you can somehow position the pointers at the appropriate nodes to do the comparison. What kind of preprocessing can I do to make that happen? We can only move forward.
What is the size of the linked list, so that I can split them into two. - Even number of elements (1-2, 2-1) - Odd number of elements (1-2-3, 2-1) Where should the middle element be added to the first list or second list? We don’t really care. We still stop comparing when we not longer have nodes in the smaller list.
First half and second half can be split. Reverse the second half
1->2 -> 2->1 1->2 -> 1->2
1->2 -> 2->1 1->2 -> 1->2
Analyze Time and Space Complexity
Time: O( ) Space: O( )
Outline the Solution
We will split the given linked list by half
Reverse the second half
Compare and check if it is palindrome
Revert the linked list to its orignal list
Find the end of the first half
Reverse the linked list
Palindrome
|
|
|
|
Palindrome Linked List excerpt: This covers the basic building blocks such as fast and slow pointers to find the middle of the linked list and reversing the linked list. tags: fast-and-slow-pointers find-middle-of-linked-list reverse-linked-list
Given the head of a singly linked list, return true if it is a palindrome.
Constraints
- The number of nodes in the list is in the range [1, 105].
- 0 <= Node.val <= 9
Follow up: Could you do it in O(n) time and O(1) space?
Thought Process
Define the Term
palindrome : Reads the same forward and backwards. Instead of string, we have numbers.
1-2 1-2-2-1
Define the Interface
Input: Head of the linked list Output: boolean (palindrome or not)
Identify the constraints
- T: O(N)
- S: O(1)
Recursive approach becomes messy in this case. Going backward is problematic (not doubly linked list).
Wishful Thinking and Working Backwards
Tower of Hanoi is a good example for working backwards. Let’s apply it to this problem. Imagine you can somehow position the pointers at the appropriate nodes to do the comparison. What kind of preprocessing can I do to make that happen? We can only move forward. What is the size of the linked list, so that I can split them into two?
- Even number of elements (1-2, 2-1)
- Odd number of elements (1-2-3, 2-1)
Where should the middle element be added to the first list or second list? We don’t really care. We still stop comparing when we no longer have nodes in the smaller list.
- First half and second half can be split.
- Reverse the second half
1->2 -> 2->1 1->2 -> 1->2
1->2 -> 2->1 1->2 -> 1->2
Solution Outline
- We will split the given linked list by half
- Reverse the second half
- Compare and check if it is palindrome
- Revert the linked list to its original list
Tasks
Find the end of the first half
Reverse the linked list
Palindrome check
Steps to solve the problem:
- Create a new linked list.
- Reverse the linked list.
- Traverse at the same time on both lists to check for palindrome.
Modification:
- Use fast and slow pointer
- Get the middle of the linked list. For the first half, reverse the elements.
- Get the other half and compare
- Use a stack - Iterative Approach
- Traverse the linked list and get the total length
- Divide that by 2
- Traverse the linked list again, for length = half
- Check the top of the stack, if there is a mismatch, return false otherwise return true
- Recursive Approach
Traversal
- Get to the base case, single node.
- Pass through inside a recursive function, a pointer. Initially the head.
What is the repeated unit of work?
- Checking if the node.val == pointer.val, if they are not the same => return false
Where do you initialize before recursion?
- Helper can be used to initialize the first and last pointers
Recursive case
If we have a helper, what are the parameters to the recursive call?
two parameters (pointers)
Comparison of two elements - Compare the first and last element. Return false if they are different
What do we do after the recursive call?
- We have reached the end of the linked list
- We can start comparing last node with the first node
- Before returning - Set the pointer to the next, currently at 2
- Traverse first half, by the time we reach middle
Implementation
|
|
Building Blocks
- Fast and Slow Pointers to Find Middle of Linked List
- Reverse Linked List
|
|
Problem Classification
Data Structures: The problem involves working with Linked Lists, a fundamental data structure.
Algorithms: The problem requires the use of specific algorithms or techniques, namely: Two-pointer technique and List reversal.
Problem Type: This is a Palindrome problem, which is a common type of problem in the realm of String and List manipulation.
Complexity Analysis: Given the two-pointer and reversal techniques used, understanding of Time and Space complexity analysis would be essential for evaluating the efficiency of the solution.
This is a Linked List manipulation problem, requiring knowledge of certain algorithms, where the task is to determine whether the given list is a Palindrome or not.
Language Agnostic Coding Drills
Understanding Linked Lists: The first fundamental concept that one must understand for this problem is how linked lists work. This includes understanding the structure of a node, what head and next refer to, and the concept of singly linked lists.
Traversal in a Linked List: The second key learning point is how to traverse through a linked list. This involves iterating over the list by continuously moving to the ’next’ node until you reach the end of the list (i.e., the next node is None).
Two-pointer Technique: This problem makes use of the slow-fast (or hare and tortoise) pointer technique, where two pointers traverse the list at different speeds. This is a common technique for detecting cycles in a list or finding the middle element, as is the case in this problem.
Reversing a Linked List: This is a critical concept required for this problem. This involves changing the ’next’ pointers of every node so that they point to the previous node instead of the next node.
Comparing Linked Lists: The final step of the problem involves comparing the reversed first half of the list to the second half of the list. This is another essential skill when working with linked lists.
Step by Step Approach:
Initialization: Start with initializing two pointers,
slow
andfast
, at the head of the linked list.Find the Middle: Traverse the linked list to find the middle node. Move
slow
one step at a time andfast
two steps at a time. Whenfast
reaches the end,slow
will be at the middle.Reverse the First Half: While finding the middle, reverse the first half of the linked list. Store the reversed part in a separate variable (
reversed_list
).Adjustment for Odd Number of Nodes: If the total number of nodes is odd, move the
slow
pointer one step further.Compare the Two Halves: Now, the problem reduces to comparing two halves of a linked list. One is the
reversed_list
and the other starts fromslow
.Final Output: If all corresponding nodes in both halves are equal, return True, else return False. If we exhaust the
reversed_list
and every value was the same for both lists, we have a palindrome.
Targeted Drills in Python
Here are the coding drills for the problem. We will implement each fundamental concept one by one and gradually build up to the final solution:
- Understanding Linked Lists: Before you start, you should know how to create a linked list. Here is how you can define a Node for a singly linked list in Python.
|
|
- Traversal in a Linked List: The next concept you should understand is how to traverse a linked list. Here is a simple code that does that:
|
|
- Two-pointer Technique: You should be comfortable using two pointers to traverse a linked list. Here is a simple code that uses this technique to find the middle of a linked list:
|
|
- Reversing a Linked List: This is a critical step for this problem. Here is how you can reverse a linked list:
|
|
- Comparing Linked Lists: The final drill is to compare two linked lists. This will be used to check if the first half and the second half of the list are the same:
|
|
Finally, you can combine all these drills to solve the problem:
|
|