Learnitweb

Problem 25: Reverse Nodes in k-Group

You are given the head of a linked list and an integer k.
Your task is to reverse the nodes of the list k at a time, and return the modified list.

If the number of nodes remaining at the end is less than k, leave them as-is.


Understanding the Problem

Example:

Input: 1 → 2 → 3 → 4 → 5, k = 2
Output: 2 → 1 → 4 → 3 → 5

Explanation:
First pair reversed: 2,1
Next pair reversed: 4,3
Remaining 5 is alone, so it stays.

Another example:

Input: 1 → 2 → 3 → 4 → 5, k = 3
Output: 3 → 2 → 1 → 4 → 5

Explanation:
First group of 3 reversed: 3,2,1
Remaining nodes (4,5) < 3, so no reversal.


Approach (Explained in Simple Language)

This problem requires chunk-based reversal of the linked list.

1. Use a dummy node

Simplifies handling head changes.

2. Check if at least k nodes remain

If fewer than k nodes remain, stop and return the list.

3. Reverse the next k nodes

Typical linked-list reversal, but only for k steps.

4. Connect the reversed segment

Keep track of:
the node before the group
the first node of the group (which becomes the last after reversal)
the node after the group

5. Move to next k-group

Repeat until no more full groups exist.

This approach ensures the entire list is processed in linear time.


Java Code

class Solution {

    public ListNode reverseKGroup(ListNode head, int k) {

        if (head == null || k == 1) {
            return head;
        }

        ListNode dummy = new ListNode(0);
        dummy.next = head;

        ListNode groupPrev = dummy;

        while (true) {

            ListNode kth = getKthNode(groupPrev, k);
            if (kth == null) {
                break;
            }

            ListNode groupNext = kth.next;

            ListNode prev = groupNext;
            ListNode curr = groupPrev.next;

            while (curr != groupNext) {
                ListNode temp = curr.next;
                curr.next = prev;
                prev = curr;
                curr = temp;
            }

            ListNode temp = groupPrev.next;
            groupPrev.next = kth;
            groupPrev = temp;
        }

        return dummy.next;
    }

    private ListNode getKthNode(ListNode start, int k) {
        while (start != null && k > 0) {
            start = start.next;
            k--;
        }
        return start;
    }
}

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

Dry Run

Input:
1 → 2 → 3 → 4 → 5
k = 2

Let’s walk step by step.

dummy → 1 → 2 → 3 → 4 → 5
groupPrev = dummy


Step 1: Find kth node

getKthNode(dummy, 2) → node with value 2
kth = 2
groupNext = 3

We will reverse nodes between groupPrev.next (1) and kth (2).


Reverse nodes 1 and 2

Initial:
prev = 3
curr = 1

Iteration 1:
temp = 2
1.next = 3
prev = 1
curr = 2

Iteration 2:
temp = 3
2.next = 1
prev = 2
curr = 3

Reversed segment:
2 → 1 → 3

Connect:

groupPrev.next = kth → 2
groupPrev becomes old start of segment → 1

List becomes:
dummy → 2 → 1 → 3 → 4 → 5
groupPrev = 1


Step 2: Find next kth node

getKthNode(1, 2) → node with value 4
kth = 4
groupNext = 5

Reverse nodes 3 and 4.

prev = 5
curr = 3

Iteration 1:
temp = 4
3.next = 5
prev = 3
curr = 4

Iteration 2:
temp = 5
4.next = 3
prev = 4
curr = 5

Reversed segment:
4 → 3 → 5

Connect:

groupPrev.next = 4
groupPrev = 3

List becomes:
2 → 1 → 4 → 3 → 5


Step 3: Attempt next kth node

getKthNode(3, 2) → returns null (only one node left)

Stop.


Final Output

2 → 1 → 4 → 3 → 5


Why This Approach Works

By splitting the list into groups of k and reversing each independently, while always keeping track of:

the node before the group
the k-th node
the head and tail of the reversed portion

we can efficiently reverse each segment without disrupting the rest of the list.

The algorithm runs in:

Time: O(n) because each node is reversed once
Space: O(1) because no extra data structure is used