Problem Statement
Given a singly linked list, the task is to segregate its nodes in such a way that all nodes with even values appear before all nodes with odd values. The relative order of even and odd elements should remain the same.
Examples
Example 1:
Input: List = [1, 2, 3, 4, 5, 6]
Output: [1, 3, 5, 2, 4, 6]
Example 2:
Input Linked List: [17, 15, 8, 12, 10, 5, 4]
Output Linked List: [8, 12, 10, 4, 17, 15, 5]
Different Approaches
1️⃣ Using Two Separate Lists
To segregate the odd and even nodes, we can traverse the linked list while maintaining two separate lists - one for even nodes and one for odd nodes. After traversing the entire list, we can simply append the odd list after the even list to achieve the desired segregation.
Algorithm:
- Traverse the linked list, maintaining two separate lists for even and odd nodes.
- After traversal, append the odd list after the even list.
- This approach requires extra space for maintaining separate lists.
Complexity Analysis:
- Time Complexity:
O(n)
- Space Complexity:
O(n)
2️⃣ In-Place Rearrangement
Intuition
The problem requires rearranging a linked list so that all nodes with even values appear before all nodes with odd values while maintaining their relative order. The key idea is to traverse the list once, separate nodes into two categories (even and odd), and then combine these two categories into a single linked list.
The intuition behind solving this efficiently involves using two pointers to build two separate lists during a single pass through the original list:
- Even List: Contains all nodes with even values.
- Odd List: Contains all nodes with odd values.
After creating these two lists, they can be connected such that all even nodes come before all odd nodes.
Algorithm:
- Initialize Pointers:
- Use four pointers to manage two lists: one for even nodes and one for odd nodes.
evenHead
andoddHead
are dummy nodes that will mark the beginning of the even and odd lists, respectively.evenTail
andoddTail
are pointers that will traverse and expand the even and odd lists, respectively.
- Traverse the Original List:
- Start from the head of the original linked list.
- For each node:
- If the node's value is even, append it to the end of the even list and move the
evenTail
pointer forward. - If the node's value is odd, append it to the end of the odd list and move the
oddTail
pointer forward.
- If the node's value is even, append it to the end of the even list and move the
- Combine the Even and Odd Lists:
- After traversing all nodes, connect the end of the even list (
evenTail
) to the start of the odd list (oddHead->next
). - Ensure the end of the odd list (
oddTail->next
) points toNULL
to mark the end of the combined list.
- After traversing all nodes, connect the end of the even list (
- Update the Head of the Linked List:
- If the even list is non-empty, set the head to
evenHead->next
. - If there are no even nodes, set the head to
oddHead->next
.
- If the even list is non-empty, set the head to
Dry Run:
Let's perform a dry run using the example linked list:
Input Linked List:17 -> 15 -> 8 -> 12 -> 10 -> 5 -> 4
Expected Output Linked List:8 -> 12 -> 10 -> 4 -> 17 -> 15 -> 5
Initialization:
evenHead = nullptr
evenTail = nullptr
oddHead = nullptr
oddTail = nullptr
+----+ +----+ +---+ +----+ +----+ +---+ +---+
| 17 |->| 15 |->| 8 |->| 12 |->| 10 |->| 5 |->| 4 |
+----+ +----+ +---+ +----+ -----+ +---+ +---+
1st Iteration:
------ ------ ----- ------ ------ ----- -----
| 17 |->| 15 |->| 8 |->| 12 |->| 10 |->| 5 |->| 4 |
------ ------ ----- ------ ------ ----- -----
^
|
current
evenHead = nullptr
evenTail = nullptr
oddHead = 17
oddTail = 17
Second Iteration:
------ ------ ----- ------ ------ ----- -----
| 17 |->| 15 |->| 8 |->| 12 |->| 10 |->| 5 |->| 4 |
------ ------ ----- ------ ------ ----- -----
^
|
current
evenHead = nullptr
evenTail = nullptr
oddHead = 17
oddTail = 17 -> 15
Third Iteration:
------ ------ ----- ------ ------ ----- -----
| 17 |->| 15 |->| 8 |->| 12 |->| 10 |->| 5 |->| 4 |
------ ------ ----- ------ ------ ----- -----
^
|
current
evenHead = 8
evenTail = 8
oddHead = 17
oddTail = 17 -> 15
Fourth Iteration:
------ ------ ----- ------ ------ ----- -----
| 17 |->| 15 |->| 8 |->| 12 |->| 10 |->| 5 |->| 4 |
------ ------ ----- ------ ------ ----- -----
^
|
current
evenHead = 8
evenTail = 8 -> 12
oddHead = 17
oddTail = 17 -> 15
Fifth Iteration:
------ ------ ----- ------ ------ ----- -----
| 17 |->| 15 |->| 8 |->| 12 |->| 10 |->| 5 |->| 4 |
------ ------ ----- ------ ------ ----- -----
^
|
current
evenHead = 8
evenTail = 8 -> 12 -> 10
oddHead = 17
oddTail = 17 -> 15
Sixth Iteration:
------ ------ ----- ------ ------ ----- -----
| 17 |->| 15 |->| 8 |->| 12 |->| 10 |->| 5 |->| 4 |
------ ------ ----- ------ ------ ----- -----
^
|
current
evenHead = 8
evenTail = 8 -> 12 -> 10
oddHead = 17
oddTail = 17 -> 15 -> 5
Seventh Iteration:
------ ------ ----- ------ ------ ----- -----
| 17 |->| 15 |->| 8 |->| 12 |->| 10 |->| 5 |->| 4 |
------ ------ ----- ------ ------ ----- -----
^
|
current
evenHead = 8
evenTail = 8 -> 12 -> 10 -> 4
oddHead = 17
oddTail = 17 -> 15 -> 5
Break of Loop:
----- ----- ---- ----- ----- ---- ----
|17 |->|15 |->|8 |->|12 |->|10 |->|5 |->|4 | -> nullptr
----- ----- ---- ----- ----- ---- ----
^
|
current
Since current is pointing to nullptr,
so break the loop and merge the odd and even list.
evenHead = 8
evenTail = 8 -> 12 -> 10 -> 4
oddHead = 17
oddTail = 17 -> 15 -> 5
evenTail->next = oddHead
oddTail->next = nullptr
8 -> 12 -> 10 -> 4 -> 17 -> 15 -> 5 -> nullptr
Code:
#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
Node(int val) : data(val), next(nullptr) {}
};
void segregateEvenOdd(Node* head) {
Node* evenHead = nullptr, *evenTail = nullptr;
Node* oddHead = nullptr, *oddTail = nullptr;
Node* current = head;
while (current != nullptr) {
if (current->data % 2 == 0) {
if (evenHead == nullptr) {
evenHead = evenTail = current;
} else {
evenTail->next = current;
evenTail = current;
}
} else {
if (oddHead == nullptr) {
oddHead = oddTail = current;
} else {
oddTail->next = current;
oddTail = current;
}
}
current = current->next;
}
if (evenHead == nullptr || oddHead == nullptr)
return;
evenTail->next = oddHead;
oddTail->next = nullptr;
// Update head to the beginning of even list
head = evenHead;
}
void printList(Node* head) {
while (head != nullptr) {
cout << head->data << " ";
head = head->next;
}
cout << endl;
}
int main() {
// Example usage
Node* head = new Node(1);
head->next = new Node(2);
head->next->next = new Node(3);
head->next->next->next = new Node(4);
head->next->next->next->next = new Node(5);
cout << "Original List: ";
printList(head);
segregateEvenOdd(head);
cout << "Segregated List: ";
printList(head);
return 0;
}
OR:
/*
Definition of singly linked list:
struct ListNode
{
int val; // Value of the node
ListNode *next; // Pointer to the next node in the list
// Default constructor
ListNode() {
val = 0;
next = NULL;
}
// Constructor to initialize the node with a value
ListNode(int data1) {
val = data1;
next = NULL;
}
// Constructor to initialize the node with a value and the next pointer
ListNode(int data1, ListNode *next1) {
val = data1;
next = next1;
}
};
*/
class Solution {
public:
// Function to rearrange the list such that odd-indexed nodes appear first
// followed by even-indexed nodes
ListNode* oddEvenList(ListNode* head) {
// Dummy node to start the list of odd-indexed nodes
ListNode* oddIndex = new ListNode(0);
ListNode* oddIndexItr = oddIndex; // Iterator for the odd-indexed list
// Dummy node to start the list of even-indexed nodes
ListNode* evenIndex = new ListNode(0);
ListNode* evenIndexItr = evenIndex; // Iterator for the even-indexed list
ListNode* iterator = head; // Iterator for traversing the input list
int count = 1; // Counter to determine odd or even index
// Traverse the input list
while (iterator != nullptr) {
// Create a new node for the current value (unnecessary memory usage here)
ListNode* temp = new ListNode(iterator->val);
if (count % 2 == 1) {
// Current node is at an odd index
oddIndexItr->next = temp; // Add the node to the odd-indexed list
oddIndexItr = oddIndexItr->next; // Move the iterator
} else {
// Current node is at an even index
evenIndexItr->next = temp; // Add the node to the even-indexed list
evenIndexItr = evenIndexItr->next; // Move the iterator
}
iterator = iterator->next; // Move to the next node in the input list
count++; // Increment the index counter
}
// Connect the last odd-indexed node to the first even-indexed node
oddIndexItr->next = evenIndex->next;
// Return the head of the rearranged list (skipping the dummy node)
return oddIndex->next;
}
};
Complexity Analysis:
- Time Complexity:
O(n)
- This is because we traverse the list once to segregate the even and odd nods, where n is the number of nodes in the linked list.
- Space Complexity:
O(1)
- For in-place rearrangement approach
O(1)
- For in-place rearrangement approach
3️⃣ Optimized Approach
Code:
class Solution {
public:
ListNode* oddEvenList(ListNode* head) {
if (!head || !head->next) {
// If the list has less than two nodes, return as is
return head;
}
// Pointers to track odd and even nodes
ListNode* odd = head;
ListNode* even = head->next;
ListNode* evenHead = even; // Store the head of the even list
// Traverse and rearrange nodes
while (even && even->next) {
odd->next = even->next; // Connect the next odd node
odd = odd->next; // Move odd pointer forward
even->next = odd->next; // Connect the next even node
even = even->next; // Move even pointer forward
}
// Connect the last odd node to the head of the even list
odd->next = evenHead;
return head; // Return the rearranged list
}
};
Complexity Analysis:
- Time Complexity:
O(N/2)x2 ~ O(N)
because we are iterating over the odd-indexed as well as the even-indexed elements. Here N is the size of the given linked list. - Space Complexity: O(1) because we have not used any extra space.