Back to Linked List
Reverse Nodes in k-Group
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.
🔹 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]
🔍 Approaches
1. Iterative with Group Reversal
We process the list in chunks of size k. For each chunk, we reverse it and link it back to the previous and next chunks.
✨ Intuition
- Use a
dummynode to handle the new head easily. - Navigate
ksteps to check if there are enough nodes to reverse. - If yes, reverse the
knodes. - Maintain
groupPrev(end of previous reversed group) and connect it to the new start of current group. - Update
groupPrevto the end of the current group (which was the start before reversal).
🔥 Algorithm Steps
- Create
dummynode pointing tohead.groupPrev = dummy. - Find the
kthnode fromgroupPrev. If not found (less than k nodes), stop. - Save
groupNext = kth.next. - Reverse the list from
groupPrev.nexttokth. - Connect
groupPrev.nextto the new head of reversed group (kth). - Connect the new tail of reversed group (original
start) togroupNext. - Update
groupPrevto the new tail. - Repeat until end of list.
⏳ Time & Space Complexity
- Time Complexity: $O(n)$, we visit each node twice (once to find range, once to reverse).
- Space Complexity: $O(1)$.
🚀 Code Implementations
C++
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* dummy = new ListNode(0, head);
ListNode* groupPrev = dummy;
while (true) {
ListNode* kth = getKth(groupPrev, k);
if (!kth) break;
ListNode* groupNext = kth->next;
// Reverse group
ListNode* prev = kth->next;
ListNode* curr = groupPrev->next;
while (curr != groupNext) {
ListNode* tmp = curr->next;
curr->next = prev;
prev = curr;
curr = tmp;
}
ListNode* tmp = groupPrev->next;
groupPrev->next = kth;
groupPrev = tmp;
}
return dummy->next;
}
ListNode* getKth(ListNode* curr, int k) {
while (curr && k > 0) {
curr = curr->next;
k--;
}
return curr;
}
};
Python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
dummy = ListNode(0, head)
groupPrev = dummy
while True:
kth = self.getKth(groupPrev, k)
if not kth:
break
groupNext = kth.next
# reverse group
prev, curr = kth.next, groupPrev.next
while curr != groupNext:
tmp = curr.next
curr.next = prev
prev = curr
curr = tmp
tmp = groupPrev.next
groupPrev.next = kth
groupPrev = tmp
return dummy.next
def getKth(self, curr, k):
while curr and k > 0:
curr = curr.next
k -= 1
return curr
Java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummy = new ListNode(0, head);
ListNode groupPrev = dummy;
while (true) {
ListNode kth = getKth(groupPrev, k);
if (kth == null) break;
ListNode groupNext = kth.next;
// Reverse group
ListNode prev = kth.next;
ListNode curr = groupPrev.next;
while (curr != groupNext) {
ListNode tmp = curr.next;
curr.next = prev;
prev = curr;
curr = tmp;
}
ListNode tmp = groupPrev.next;
groupPrev.next = kth;
groupPrev = tmp;
}
return dummy.next;
}
private ListNode getKth(ListNode curr, int k) {
while (curr != null && k > 0) {
curr = curr.next;
k--;
}
return curr;
}
}
🌍 Real-World Analogy
Flipping Pancakes in Batches:
Imagine a stack of pancakes. You want to flip them in batches of 3.
- You slide a spatula under the 3rd pancake.
- You lift the top 3 and flip them over onto the plate.
- Then you slide the spatula under the 6th pancake (relative to original order) and flip the next batch of 3.
- If fewer than 3 remain, you leave them as is.
🎯 Summary
✅ Complex Pointer Manipulation: Good practice for interview scenarios.
✅ Modular Logic: Breaking it down into "get kth" and "reverse logic" simplifies implementation.
Solution Code
O(n) TimeO(1) Space
#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
class Solution {
public:
ListNode *reverseKGroup(ListNode *head, int k) {
ListNode *dummy = new ListNode(0, head);
ListNode *groupPrev = dummy;
while (true) {
ListNode *kth = getKth(groupPrev, k);
if (!kth)
break;
ListNode *groupNext = kth->next;
// Reverse group
ListNode *prev = kth->next;
ListNode *curr = groupPrev->next;
while (curr != groupNext) {
ListNode *tmp = curr->next;
curr->next = prev;
prev = curr;
curr = tmp;
}
ListNode *tmp = groupPrev->next;
groupPrev->next = kth;
groupPrev = tmp;
}
return dummy->next;
}
ListNode *getKth(ListNode *curr, int k) {
while (curr && k > 0) {
curr = curr->next;
k--;
}
return curr;
}
};
void printList(ListNode *head) {
while (head) {
cout << head->val << (head->next ? "->" : "");
head = head->next;
}
cout << endl;
}
int main() {
Solution sol;
ListNode *head = new ListNode(
1, new ListNode(2, new ListNode(3, new ListNode(4, new ListNode(5)))));
cout << "Original: ";
printList(head);
head = sol.reverseKGroup(head, 2);
cout << "Reversed k=2: ";
printList(head); // 2->1->4->3->5
return 0;
}
SYSTEM STABLEUTF-8 • STATIC_RENDER