You are given the head of a singly linked list head and a positive integer k.
You must reverse the first k nodes in the linked list, and then reverse the next k nodes, and so on. If there are fewer than k nodes left, leave the nodes as they are.
Return the modified list after reversing the nodes in each group of k.
You are only allowed to modify the nodes' next pointers, not the values of the nodes.
Example 1:
Input: head = [1,2,3,4,5,6], k = 3
Output: [3,2,1,6,5,4]Example 2:
Input: head = [1,2,3,4,5], k = 3
Output: [3,2,1,4,5]Constraints:
n.1 <= k <= n <= 1000 <= Node.val <= 100
You should aim for a solution with O(n) time and O(1) space, where n is the length of the given list.
A brute-force solution would involve storing the linked list node values in an array, reversing the k groups one by one, and then converting the array back into a linked list, requiring extra space of O(n). Can you think of a better way? Perhaps you could apply the idea of reversing a linked list in-place without using extra space.
We can avoid extra space by reversing each group in-place while keeping track of the head of the next group. For example, consider the list [1, 2, 3, 4, 5] with k = 2. First, we reverse the group [1, 2] to [2, 1]. Then, we reverse [3, 4], resulting in [2, 1, 4, 3, 5]. While reversing [3, 4], we need to link 1 to 4 and also link 3 to 5. How can we efficiently manage these pointers?
We create a dummy node to handle modifications to the head of the linked list, pointing its next pointer to the current head. We then iterate k nodes, storing the address of the next group's head and tracking the tail of the previous group. After reversing the current group, we reconnect it by linking the previous group's tail to the new head and the current group's tail to the next group's head. This process is repeated for all groups, and we return the new head of the linked list.
Before attempting this problem, you should be comfortable with:
To reverse nodes in groups of k, we first check whether the current segment contains at least k nodes.
This gives a clean top-down approach:
solve the rest of the list first, then fix the current group.
Start at the given head and try to move forward k nodes.
group.k, return the current head unchanged.If exactly k nodes exist:
k nodes (cur).k nodes:k nodes:head.next in tmphead.next to the result of the recursive callk nodes, return the new head of this group.The recursion ensures each segment is reversed and correctly connected to the next processed segment.
# 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]:
cur = head
group = 0
while cur and group < k:
cur = cur.next
group += 1
if group == k:
cur = self.reverseKGroup(cur, k)
while group > 0:
tmp = head.next
head.next = cur
cur = head
head = tmp
group -= 1
head = cur
return headWe reverse the list one k-sized group at a time using pointers, without recursion.
Key ideas:
k nodes left, we stop (leave the rest as-is).By repeating this process, we reverse every full group of k nodes while keeping the rest of the list intact.
Create a dummy node pointing to head.
Set groupPrev = dummy (the node just before the current group).
Loop:
getKth(groupPrev, k) to find the k-th node from groupPrev.kth is null, there are fewer than k nodes left → break.Let:
groupNext = kth.next (first node after the current group).prev = groupNextcurr = groupPrev.next (first node in the current group)Reverse the current group:
curr != groupNext:curr.next in tmp.curr.next to prev.prev to curr.curr to tmp.After reversing:
groupPrev.next is now the start of the reversed group (kth node).tmp = groupPrev.next before rewiring).groupPrev.next = kth.groupPrev = tmp (now the end of the reversed group).Repeat steps 2–5 until no more full k-groups remain.
Return dummy.next as the new head of the list.
# 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
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 currWhen there are fewer than k nodes remaining at the end of the list, they should be left as-is. A common mistake is attempting to reverse these remaining nodes anyway, which violates the problem requirements.
After reversing a k-group, you must correctly connect the reversed segment back to the rest of the list. Failing to update groupPrev.next to point to the new head of the reversed segment (which was the k-th node) results in a broken list.
The original first node of each k-group becomes the last node after reversal. You need to save a reference to it before rewiring pointers, as it becomes the new groupPrev for the next iteration.
When checking if there are at least k nodes available, ensure your counting logic is correct. Starting the count at 0 vs 1, or using < vs <= incorrectly, can cause you to reverse groups of the wrong size.
Without a dummy node before the head, handling the first k-group requires special case logic since there is no groupPrev node. Using a dummy simplifies the code and eliminates edge cases for updating the head of the list.