LeetCode - Reverse Nodes in k-Group
Problem statement
Given the head of a linked list, reverse the nodes of the list k at a time, and return the modified list.
k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes, in the end, should remain as it is.
You may not alter the values in the list's nodes, only nodes themselves may be changed.
Problem statement taken from: https://leetcode.com/problems/reverse-nodes-in-k-group
Example 1:

Input: head = [1, 2, 3, 4, 5], k = 2
Output: [2, 1, 4, 3, 5]
Example 2:

Input: head = [1, 2, 3, 4, 5], k = 3
Output: [3, 2, 1, 4, 5]
Constraints:
- The number of nodes in the list is n.
- 1 <= k <= n <= 5000
- <= Node.val <= 1000
Follow-up: Can you solve the problem in O(1) extra memory space?
Explanation
Reverse a linked list
We can use the standard Reverse linked list code with a slight modification. We pass the count k to the method, which reverses the sublist of size k. We should keep the track of the next node and the previous node. These are required to point the pointers of the current sublist correctly to our previous sublist.
A C++ snippet of this approach is as follows:
ListNode* reverse(ListNode* head, int k) {
if (!head)
return NULL;
ListNode* current = head;
ListNode* next = NULL;
ListNode* prev = NULL;
int count = 0;
while (current != NULL && count < k) {
next = current->next;
current->next = prev;
prev = current;
current = next;
count++;
}
if (next != NULL)
head->next = reverse(next, k);
return prev;
}The time complexity of this approach is O(n). The space complexity is O(n / k). For a linked list of size n, we make n/k or n/k + 1 calls during recursion.
Optimized solution: Iterative
We can optimize the space by using the above approach without recursion. We keep track of the previous, current, and next nodes while reversing the linked list in a set of size k. Once the sublist of size k is reversed we update the previous, current, and next node correctly. We repeat this approach till the list is traversed or the last sublist is less than size k.
Let's check the algorithm
Algorithm
- if !head || k == 1
- return head
- set ListNode *temp = new ListNode(1)
temp->next = head
- set ListNode *prev, *current, *next = temp
set count = 0
initialize index and i variables
// count the size of the list
- loop while current
- current = current->next
- count++
- while end
- loop while next
- set current = prev->next
- set next = current->next
// if the last sublist is less than size k
// we keep the list as it is.
// Hence setting index = 0.
- index = count > k ? k : 0
- loop for i = 1; i < index; i++
- set current->next = next->next
next->next = prev->next
prev->next = next
next = current->next
- for end
- set prev = current
- update count = count - k
- for end
- return temp->next
The time complexity of the above approach is O(n). The space complexity is O(1).
Let's check our algorithm in C++, Golang, and JavaScript.
C++ solution
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
if(!head || k == 1) {
return head;
}
ListNode *temp = new ListNode(1);
temp->next = head;
ListNode *prev = temp, *current = temp, *next = temp;
int count = 0, index, i;
while(current) {
current = current->next;
count++;
}
while(next) {
current = prev->next;
next = current->next;
index = count > k ? k : 0;
for(i = 1; i < index; i++) {
current->next = next->next;
next->next = prev->next;
prev->next = next;
next = current->next;
}
prev = current;
count -= k;
}
return temp->next;
}
};Golang solution
func reverseKGroup(head *ListNode, k int) *ListNode {
if head == nil || k == 1 {
return head
}
temp := &ListNode{1, nil}
temp.Next = head
prev, current, next := temp, temp, temp
count, index, i := 0, 0, 0
for current != nil {
current = current.Next
count++
}
for next != nil {
current = prev.Next
next = current.Next
if count > k {
index = k
} else {
index = 0
}
for i = 1; i < index; i++ {
current.Next = next.Next
next.Next = prev.Next
prev.Next = next
next = current.Next
}
prev = current
count -= k
}
return temp.Next
}JavaScript solution
var reverseKGroup = function(head, k) {
if(!head || k == 1) {
return head;
}
let temp = new ListNode(1, null);
temp.next = head;
let prev = temp, current = temp, next = temp;
let count = 0, index, i;
while(current) {
current = current.next;
count++;
}
while(next) {
current = prev.next;
next = current.next;
index = count > k ? k : 0;
for(i = 1; i < index; i++) {
current.next = next.next;
next.next = prev.next;
prev.next = next;
next = current.next;
}
prev = current;
count -= k;
}
return temp.next;
};Dry Run
Let's dry-run our algorithm to see how the solution works.
Input: head = [1, 2, 3, 4, 5]
k = 2
Step 1: if !head || k == 1
head -> [1, 2, 3, 4, 5] || 3 == 1
false
Step 2: temp = new ListNode(1)
-> [1]
temp->next = head
temp -> [1, 1, 2, 3, 4, 5]
head -> [1, 2, 3, 4, 5]
Step 3: ListNode *prev = temp, *current = temp, *next = temp
count = 0
index, i
Step 4: loop while current
current = current->next
count++
This will count the size of linked list.
count = 5
Step 5: loop while next
current = prev->next
= [1, 2, 3, 4, 5]
next = current->next
= [2, 3, 4, 5]
index = count > k ? k : 0
= 5 > 2 ? 2 : 0
= 2
loop for i = 1; i < 2
1 < 2
true
current->next = next->next
= [3, 4, 5]
next->next = prev->next
= [1, 3, 4, 5]
prev->next = next
= [2, 1, 3, 4, 5]
next = current->next
= [3, 4, 5]
i++
i = 2
loop for i < 2
2 < 2
false
prev = current
= [1, 3, 4, 5]
count = count - k
= 5 - 2
= 3
Step 6: loop while next
next = [3, 4, 5]
current = prev->next
= [3, 4, 5]
next = current->next
= [4, 5]
index = count > k ? k : 0
= 3 > 2 ? 2 : 0
= 2
loop for i = 1; i < 2
1 < 2
true
current->next = next->next
= [3, 5]
next->next = prev->next
= [1, 4, 5]
prev->next = next
= [4, 3, 5]
next = current->next
= [5]
i++
i = 2
loop for i < 2
2 < 2
false
prev = current
= [5]
count = count - k
= 3 - 2
= 1
temp = [2, 1, 4, 3, 5]
Step 7: loop while next
next = [5]
current = prev->next
= [5]
next = current->next
= nil
index = count > k ? k : 0
= 1 > 2 ? 2 : 0
= 0
loop for i = 1; i < 0
1 < 0
false
prev = current
= [5]
count = count - k
= 1 - 2
= -1
Step 8: loop while next
next = nil
false
Step 9: return temp->next
temp = [1, 2, 1, 4, 3, 5]
temp->next = [2, 1, 4, 3, 5]
We return the answer as [2, 1, 4, 3, 5].