Reverse Nodes in k-Group

Updated on 01 July, 2025
Reverse Nodes in k-Group header image

Problem Statement

Given a linked list's head node and an integer k, the task involves reversing every consecutive subset of k nodes in the list. The head of this linked list and the integer k are your inputs. Here, k is always a positive integer and it is ensured that k is less than or equal to the total number of nodes in the linked list (denoted as n). If the total number of nodes is not a multiple of k, the nodes in the final segment that are less than k should be left as is, without being reversed. It's important to note that you should not modify the node values during the reversal process; only the links between the nodes should be rearranged.

Examples

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
  • 0 <= Node.val <= 1000

Approach and Intuition

The problem requires us to reverse parts of the linked list, specifically every k nodes, if possible, until the end of the list. Here’s how we intuitively grasp this challenge and approach solving it:

  • First, understand that each segment of k nodes needs to be independently reversed.

  • To reverse a segment:

    1. Track the start of the segment.
    2. Disconnect the segment from the list.
    3. Reverse the segment using standard linked list reversal techniques (changing next pointers).
    4. Reconnect the reversed segment back to the main list.
  • As the segments are reversed:

    1. Maintain pointers for the current node and the next node, alongside a previous segment's last node to link the reversed segment back to the main list.
  • Consider the edge cases:

    • If nodes left in a segment are fewer than k, leave them unchanged.
    • Deal with varied list lengths from 1 to the limit (5000 nodes).
  • Given the operations needed per segment are constant and each node is visited a constant number of times, the overall complexity should be linear concerning the number of nodes.

By understanding and leveraging these steps and considerations, we efficiently tackle the problem of reversing nodes of the linked list in segments of k, leveraging straightforward linked list manipulation techniques.

Analyzing the provided examples:

  • For a linked list head = [1,2,3,4,5] and k = 2, the expected output is [2,1,4,3,5]. Here, every two nodes are reversed, and since 5 is alone in the end segment with less than k nodes, it remains as it is.
  • Similarly, for k = 3, the initial three nodes [1,2,3] are reversed to [3,2,1], and the tail [4,5] with less than k nodes remains unchanged, forming [3,2,1,4,5] as the final list.

This example clearly illustrates the reversal of segments and the handling of trailing segments with fewer than k nodes.

Solutions

  • C++
  • Java
  • C
  • JavaScript
  • Python
cpp
class Solution {
public:
    ListNode* reverseList(ListNode* headNode, int k) {
        ListNode* reversedHead = nullptr;
        ListNode* current = headNode;
        while (k > 0) {
            ListNode* nextNode = current->next;
            current->next = reversedHead;
            reversedHead = current;
            current = nextNode;
            k--;
        }
        return reversedHead;
    }
    ListNode* reverseKNodes(ListNode* head, int k) {
        ListNode* currentNode = head;
        ListNode* tail = nullptr;
        ListNode* finalHead = nullptr;
        while (currentNode != nullptr) {
            int count = 0;
            currentNode = head;
            while (count < k && currentNode != nullptr) {
                currentNode = currentNode->next;
                count++;
            }
            if (count == k) {
                ListNode* reversedHead = this->reverseList(head, k);
                if (finalHead == nullptr) finalHead = reversedHead;
                if (tail != nullptr) tail->next = reversedHead;
                tail = head;
                head = currentNode;
            }
        }
        if (tail != nullptr) tail->next = head;
        return finalHead == nullptr ? head : finalHead;
    }
};

This article provides a concise explanation of how to reverse nodes in groups of k using C++ in a linked list. The solution involves defining a helper function reverseList to reverse a segment of the list, and a main function reverseKNodes to manage the overall process.

  • First, implement the reverseList function that takes the head of a sublist and the integer k:

    • Initialize two pointers, reversedHead set to nullptr, and current to headNode.
    • Use a loop to reverse the nodes. In each iteration, detach the next node, link it to the reverse growing list (reversedHead), and then update current.
    • After k iterations, the sublist is reversed, and reversedHead points to the new head of this sublist.
  • Next, in the reverseKNodes function:

    • Initialize three pointers, currentNode to head, tail to nullptr, and finalHead to nullptr.
    • Use a loop to traverse the list, checking groups of k nodes:
      • Count nodes to ensure at least k nodes remain for reversal.
      • If there are k nodes, use reverseList to reverse them.
      • Manage the head pointers properly; set finalHead if it's nullptr.
      • Link the reversed group back to the main list via tail.
      • Update tail and head to prepare for the next group.
    • Outside the loop, connect any leftover nodes by linking tail->next to head.
  • The function returns the new head of the list, finalHead, or head if no nodes were reversed.

This approach efficiently rearranges nodes in chunks, preserving group order while modifying pointers in-place for an optimal solution to the problem of reversing nodes in k-groups in a linked list.

java
class Solution {
    public ListNode reverseKNodes(ListNode current, int k) {
        ListNode previous = null;
        ListNode nextNode;
        while (k > 0) {
            nextNode = current.next;
            current.next = previous;
            previous = current;
            current = nextNode;
            k--;
        }
        return previous;
    }
    
    public ListNode reverseGroupsOfK(ListNode head, int k) {
        ListNode current = head;
        ListNode previousTail = null;
        ListNode newHead = null;
        while (current != null) {
            int count = 0;
            ListNode countNode = current;
            while (count < k && countNode != null) {
                countNode = countNode.next;
                count++;
            }
                
            if (count == k) {
                ListNode reversedHead = this.reverseKNodes(current, k);
                if (newHead == null) newHead = reversedHead;
                if (previousTail != null) previousTail.next = reversedHead;
    
                previousTail = current;
                current = countNode;
            }
        }
    
        if (previousTail != null) previousTail.next = current;
    
        return newHead != null ? newHead : head;
    }
}

This solution outlines how to reverse nodes in groups of k within a linked list using Java. The main functionality is divided into two methods within the Solution class:

  • reverseKNodes(ListNode current, int k): This method is responsible for reversing k nodes in the linked list starting from the node referred to as current. A temporary node nextNode is used to keep track of the nodes succeeding the current node as the links are reversed. The reversal is accomplished using a standard technique where links are adjusted backwards using a previous node pointer until k nodes are processed. After the loop, previous points to the new head of the reversed segment.

  • reverseGroupsOfK(ListNode head, int k): This method uses the reverseKNodes to reverse every group of k nodes in the entire list. It starts by initializing pointers such as current for tracking the current node, previousTail for connection purposes, and newHead to mark the head of the modified list. The method entails counting nodes to determine if a full group of k is present. If a full group is found, it is reversed using reverseKNodes. Pointers like previousTail are then adjusted to ensure the segments are correctly connected as the list is modified in chunks. The loop continues until all nodes are processed. The method returns the new head of the list if modifications were made; otherwise, it returns the original head.

In essence, this implementation is efficient in that it only traverses the list once and performs in-place reversal of the nodes, effectively minimizing additional space usage and ensuring optimal performance. Use these methods to efficiently rearrange nodes in specified group sizes for linked lists in Java applications.

c
struct ListNode* invertSegment(struct ListNode* start, int count) {
    struct ListNode* reversedPart = NULL;
    struct ListNode* current = start;
    while (count > 0) {
        struct ListNode* nextElement = current->next;
        current->next = reversedPart;
        reversedPart = current;
        current = nextElement;
        count--;
    }
    return reversedPart;
}
    
struct ListNode* reverseKNodes(struct ListNode* start, int count) {
    struct ListNode* current = start;
    struct ListNode* endOfReversed = NULL;
    struct ListNode* finalHead = NULL;
    while (current != NULL) {
        int nodeCount = 0;
        current = start;
        while (nodeCount < count && current != NULL) {
            current = current->next;
            nodeCount++;
        }
        if (nodeCount == count) {
            struct ListNode* newSegmentHead = invertSegment(start, count);
            if (finalHead == NULL) finalHead = newSegmentHead;
            if (endOfReversed != NULL) endOfReversed->next = newSegmentHead;
            endOfReversed = start;
            start = current;
        }
    }
    if (endOfReversed != NULL) endOfReversed->next = start;
    return finalHead == NULL ? start : finalHead;
}

The provided C code offers a solution to the "Reverse Nodes in k-Group" problem, where the task is to reverse every group of k nodes in a singly linked list. If the number of nodes in the list is not a multiple of k, the last nodes remain as-is.

The solution is divided into two main functions:

  • invertSegment(struct ListNode* start, int count): This function takes a segment of count nodes starting from start and reverses them. It implements the reversal using a classic iterative linked list reversal technique by traversing the nodes and adjusting their links. The reversedPart variable is used as the new head of the reversed segment.

  • reverseKNodes(struct ListNode* start, int count): This function manages the overall process of segmenting the linked list and applying the invertSegment function to each valid segment. It keeps track of the start of segments yet to be processed with the start variable, and the end of the last fully processed and reversed segment with endOfReversed. It also ensures to set the next pointer of the last node of a reversed segment to the head of the next reversed segment, linking all reversed parts together. Finally, it handles the scenario where the last segment is shorter than k and thus should not be reversed.

By executing this code:

  1. The reverseKNodes is initially called with the head of the list and k as parameters.
  2. The function iteratively checks if there's a full segment of k nodes to process by counting nodes.
  3. If a full segment is available, it uses invertSegment to reverse it.
  4. The function continues until no more full segments are available.
  5. The end of the last reversed segment is linked to the start of any remaining unreversed part of the list.

The final result is either the completely processed list with some segments reversed or the original list if k exceeds the list's length.

js
var reverseSubList = function (startNode, length) {
    let reversedListHead = null;
    let current = startNode;
    while (length > 0) {
        let nextTemp = current.next;
        current.next = reversedListHead;
        reversedListHead = current;
        current = nextTemp;
        length--;
    }
    return reversedListHead;
};
var reverseByGroup = function (listHead, groupSize) {
    let currentPointer = listHead;
    let prevGroupTail = null;
    let resultListHead = null;
    while (currentPointer !== null) {
        let count = 0;
        currentPointer = listHead;
        while (count < groupSize && currentPointer !== null) {
            currentPointer = currentPointer.next;
            count++;
        }
        if (count === groupSize) {
            let newGroupHead = reverseSubList(listHead, groupSize);
            if (resultListHead === null) resultListHead = newGroupHead;
            if (prevGroupTail !== null) prevGroupTail.next = newGroupHead;
            prevGroupTail = listHead;
            listHead = currentPointer;
        }
    }
    if (prevGroupTail !== null) prevGroupTail.next = listHead;
    return resultListHead === null ? listHead : resultListHead;
};

The provided JavaScript solution reverses nodes in k-group in a linked list. The process is divided into two main functions:

  • reverseSubList(startNode, length): Reverses a sublist of the linked list. Beginning at startNode, it reverses length nodes. It manages pointers to keep track of the reversed list as it progresses through the sublist.

  • reverseByGroup(listHead, groupSize): Manages the overall process of dividing the main list into groups of size groupSize and applies the reverseSubList function to each group. It makes use of additional pointers to connect the last node of the previous reversed group to the first node of the next group after reversal.

The main steps include:

  1. Traverse through the linked list, counting nodes to determine if there is a full group of groupSize to reverse.
  2. If a full group is present, reverse the nodes in that group using reverseSubList.
  3. After reversing, adjust pointers to ensure the newly reversed group links correctly to the rest of the list.
  4. If the end of the list is reached and there’s a group smaller than groupSize, it's left as is.
  5. Return the head of the new list, which may be different if the initial portion of the list was reversed.

This solution ensures that k-sized groups are reversed and correctly linked within the list, handling edge cases such as no reversal needed when group sizes exceed list length or when groupSize is one.

python
class Solution:
        
    # Method to reverse a segment of the linked list
    def reverseSegment(self, start_node, segment_size):
        reversed_head, current = None, start_node
        while segment_size:
            next_temp = current.next
            current.next = reversed_head
            reversed_head = current
            current = next_temp
            segment_size -= 1
        return reversed_head
    
    # Main method to reverse nodes in k groups
    def reverseGroups(self, start_node: ListNode, group_size: int) -> ListNode:
        current = start_node
        last_tail = None
        first_head = None
            
        while current:
            node_count = 0
            current = start_node
            while node_count < group_size and current:
                current = current.next
                node_count += 1
                    
            if node_count == group_size:
                reversed_head = self.reverseSegment(start_node, group_size)
                    
                if not first_head:
                    first_head = reversed_head
                    
                if last_tail:
                    last_tail.next = reversed_head
                    
                last_tail = start_node
                start_node = current
            
        if last_tail:
            last_tail.next = start_node
            
        return first_head if first_head else start_node

In this solution, the task is to reverse nodes of a linked list in groups of 'k' using Python. The implementation consists of two main components: reversing a segment of the linked list, and executing this reversal across specified intervals as dictated by 'k'.

  • The reverseSegment function takes a starting node and the size of the segment to be reversed. It iterates through the list, reversing pointers until the segment is fully reversed, and then returns the new head of the reversed segment.

  • The reverseGroups function orchestrates the overall reversal process in groups. It traverses the linked list, checking the size of each group to ensure it matches 'k'. If it does, the segment starting from the current node is reversed using reverseSegment. This function maintains pointers to the head of the first reversed segment and the tail of the last segment to manage connections between reversed and non-reversed parts of the list effectively.

  • After all possible groups of size 'k' have been reversed, any remaining nodes (if the total number of nodes isn't a multiple of 'k') are appended in their original order.

You can leverage this approach in scenarios where processing or manipulation of data in structured segments is required, adapting the methodology to various data types and structures beyond singly-linked lists.

Comments

No comments yet.