Difficulty: Medium, Asked-in: Facebook, Microsoft, Amazon, Adobe, Yahoo.
Key takeaway: An excellent problem to learn problem-solving using iteration and recursion in a linked list.
Given a singly linked list, write a program to swap every two adjacent nodes and return its head. If the number of nodes is odd, then we need to pair-wise swap all the elements except the last element.
Input: 12->42->9->30->56->20->NULL
Output: 42->12->30->9->20->56->NULL
Input: 1->2->3->4->5->NULL
Output: 2->1->4->3->5->NULL
The idea is to traverse the linked list linearly, pick the nodes in pairs, and swap their links. By the end of the process, we return the head pointer of the modified list. The idea looks simple, but we need to be careful with the pointer's movement.
We define a function pairWiseSwap(ListNode head), which takes the head of the linked list as input and returns the head pointer of the pair-wise swapped linked list.
Step 1: If the linked list is empty or there is a single node, we return the head as an output, i.e., if (head == NULL || head->next == NULL), return head. Otherwise, we move forward in a loop to pick nodes in pairs and swap their links.
Step 2: Before starting the loop:
Step 3: Now we run a loop to swap list nodes in pairs by changing links. What will be the loop condition? The idea is simple: We are considering two nodes simultaneously, so we run the loop till currNode and currNode->next are not NULL. Now we perform the pointers swapping inside the while loop.
Step 4: After the completion of the while loop, we have completed the pairwise swapping, and the newHead pointer points to the correct head of the modified linked list. So we return newHead.
The overall idea is to use two pointers (currNode and temp) to perform the pairwise swapping and update the necessary pointers at each step to ensure the correct connections between nodes.
ListNode* pairWiseSwap(ListNode* head)
{
if (head == NULL || head->next == NULL)
return head;
ListNode* currNode = head;
ListNode* newHead = head->next;
while (currNode != NULL && currNode->next != NULL)
{
ListNode* temp = currNode->next;
currNode->next = currNode->next->next;
temp->next = currNode;
currNode = currNode->next;
if (currNode != NULL && currNode->next != NULL)
temp->next->next = currNode->next;
}
return newHead;
}
def pairWiseSwap(head):
if head is None or head.next is None:
return head
currNode = head
newHead = head.next
while currNode is not None and currNode.next is not None:
temp = currNode.next
currNode.next = currNode.next.next
temp.next = currNode
currNode = currNode.next
if currNode is not None and currNode.next is not None:
temp.next.next = currNode.next
return newHead
class PairwiseSwapLinkedList
{
public static ListNode pairWiseSwap(ListNode head)
{
if (head == null || head.next == null)
return head;
ListNode currNode = head;
ListNode newHead = head.next;
while (currNode != null && currNode.next != null)
{
ListNode temp = currNode.next;
currNode.next = currNode.next.next;
temp.next = currNode;
currNode = currNode.next;
if (currNode != null && currNode.next != null)
temp.next.next = currNode.next;
}
return newHead;
}
}
We are doing a single traversal of the linked list and performing pointer movement operations at each iteration. In other words, we are doing constant operations with each node in the linked list. So, time complexity = O(n), where n is the number of nodes. We are using constant extra space, so space complexity = O(1).
Now a critical question is: Can we solve this problem using the solution of a smaller sub-problem i.e. using recursion? If yes, then what would be the recursive structure? Let's think!
Suppose there are n nodes in the linked list, and we swap the first two nodes. Now the problem will get reduced to swapping the remaining n - 2 nodes in pairs. So the solution idea would be to swap the first two nodes and call the same function for the remaining list if there are more than two nodes in the list. By the end of the process, we should return the head of the modified linked list.
Recursive structure: Pair-wise swapping of linked list size of n = Swapping the first two nodes + Pair-wise swapping of the remaining linked list of size n - 2 recursively.
Now, we swap the first pair of nodes i.e. head and head->next.
ListNode* pairWiseSwap(ListNode* head)
{
if (head == NULL || head->next == NULL)
return head;
ListNode* remainingListHead = head->next->next;
ListNode* newHead = head->next;
newHead->next = head;
head->next = pairWiseSwap(remainingListHead);
return newHead;
}
def pairWiseSwap(head):
if head is None or head.next is None:
return head
remainingListHead = head.next.next
newHead = head.next
newHead.next = head
head.next = pairWiseSwap(remainingListHead)
return newHead
public class PairwiseSwapLinkedList
{
public static ListNode pairWiseSwap(ListNode head)
{
if (head == null || head.next == null)
return head;
ListNode remainingListHead = head.next.next;
ListNode newHead = head.next;
newHead.next = head;
head.next = pairWiseSwap(remainingListHead);
return newHead;
}
}
Suppose the total number of nodes in the linked list is n.
The space complexity depends on the size of the recursion call stack which will be equal to the height of the recursion tree. There would be a total n/2 number of recursive calls till our recursion reach the base case, so the height of the recursion tree = n/2. For this, recursion will use a call stack of size n/2, so space complexity = O(n). Think!
We can solve this problem using another idea: Swapping node values in pairs instead of changing pointers. The solution begins with the first node and keeps swapping values in pairs till we reach the NULL node. Here we swap the data of the nodes keeping their addresses as it is.
Efficiency note: If data contains too many fields, then we need to perform several swap operations. So swapping links is an efficient idea in comparison to swapping values! Think!
ListNode* pairWiseSwap(ListNode* head)
{
if (head == NULL || head->next == NULL)
return head;
ListNode* temp = head;
while (temp != NULL && temp->next != NULL)
{
swap(temp->val, temp->next->val);
temp = temp->next->next;
}
return head;
}
def pairWiseSwap(head):
if head is None or head.next is None:
return head
temp = head
while temp is not None and temp.next is not None:
temp.val, temp.next.val = temp.next.val, temp.val
temp = temp.next.next
return head
public class PairwiseSwapLinkedList
{
public static ListNode pairWiseSwap(ListNode head)
{
if (head == null || head.next == null)
return head;
ListNode temp = head;
while (temp != null && temp.next != null)
{
int tempVal = temp.val;
temp.val = temp.next.val;
temp.next.val = tempVal;
temp = temp.next.next;
}
return head;
}
}
We are doing a single traversal of the linked list and performing data swapping operations at each iteration. Suppose we have m data fields in a linked list node, then we need to swap each data field for each pair of nodes. In other words, we need to perform O(m) data swapping operations for each node during the swapping operation.
If the total number of nodes is n, time complexity = Time complexity of data swapping for each pair of nodes * total number of node pairs = O(m) * n/2 = O(mn).
We are using constant extra space, so space complexity = O(1).
We can also think to implement the above approach recursively. If there are 2 or more than 2 nodes in the linked list then we swap the first two nodes and recursively swap pair-wise nodes for the remaining linked list.
Recursive structure: pairWiseSwap(head) = swap(head->data, head->next->data) + pairWiseSwap(head->next->next)
Base case: if (head == NULL || head->next == NULL), return head.
ListNode* pairWiseSwap(ListNode* head)
{
if (head == NULL || head->next == NULL)
return head;
else
{
swap(head->val, head->next->val);
pairWiseSwap(head->next->next);
return head;
}
}
def pairWiseSwap(head):
if head is None or head.next is None:
return head
head.val, head.next.val = head.next.val, head.val
pairWiseSwap(head.next.next)
return head
public class PairwiseSwapLinkedList
{
public static ListNode pairWiseSwap(ListNode head)
{
if (head == null || head.next == null)
return head;
else
{
int tempVal = head.val;
head.val = head.next.val;
head.next.val = tempVal;
pairWiseSwap(head.next.next);
return head;
}
}
}
Suppose the total number of nodes in the linked list is n.
The space complexity depends on the size of the recursion call stack which will be equal to the height of the recursion tree. There would be a total n/2 number of recursive calls till our recursion reach the base case. For this, the size of the call stack would be O(n), so space complexity = O(n).
If you have any queries or feedback, please write us at contact@enjoyalgorithms.com.Enjoy learning, Enjoy coding, Enjoy algorithms!