Reverse Nodes in Even Length Groups solution and explanation
9 more videos on this problem
LeetCode 2074: Reverse Nodes in Even Length GroupsEngineering Digest · 18:22 · 3K views
2074. Reverse Nodes in Even Length Groups (Leetcode Medium)Programming Live with Larry · 9:09 · 2K views
Reverse Nodes in Even Length Groups LeetCodeShivanshu Verma · 9:39 · 1K views
2074 Reverse Nodes in Even Length GroupsMath Geeks · 5:13 · 1K views
【每日一题】LeetCode 2074. Reverse Nodes in Even Length GroupsHuifeng Guan · 19:43 · 646 views
Educative.io Day 27: Reverse Nodes in Even Length Groups | In-place Linked List Reversal PatternMayowa Daniel · 13:58 · 461 views
Reverse Nodes In Even Length GroupsOwen Wu · 10:17 · 305 views
Reverse Nodes in Even Length Groups - Leetcode Weekly Contest 267Gopala Krishna Reddy Maguluri · 0:53 · 236 views
Reverse Nodes in Even Length Groups - Linked List Solution ExplainedCodeLucky · 3:07 · 54 views
LeetCode 2074: Reverse Nodes in Even Length GroupsAlitaCode · 30:21 · 31 views
The problem
You are given the head of a linked list.
The nodes in the linked list are sequentially assigned to non-empty groups whose lengths form the sequence of the natural numbers (1, 2, 3, 4, ...). The length of a group is the number of nodes assigned to it. In other words,
- The
1stnode is assigned to the first group. - The
2ndand the3rdnodes are assigned to the second group. - The
4th,5th, and6thnodes are assigned to the third group, and so on.
Note that the length of the last group may be less than or equal to 1 + the length of the second to last group.
Reverse the nodes in each group with an even length, and return the head of the modified linked list.
Example 1:
Input: head = [5,2,6,3,9,1,7,3,8,4] Output: [5,6,2,3,9,1,4,8,3,7] Explanation: - The length of the first group is 1, which is odd, hence no reversal occurs. - The length of the second group is 2, which is even, hence the nodes are reversed. - The length of the third group is 3, which is odd, hence no reversal occurs. - The length of the last group is 4, which is even, hence the nodes are reversed.
Example 2:
Input: head = [1,1,0,6] Output: [1,0,1,6] Explanation: - The length of the first group is 1. No reversal occurs. - The length of the second group is 2. The nodes are reversed. - The length of the last group is 1. No reversal occurs.
Example 3:
Input: head = [1,1,0,6,5] Output: [1,0,1,5,6] Explanation: - The length of the first group is 1. No reversal occurs. - The length of the second group is 2. The nodes are reversed. - The length of the last group is 2. The nodes are reversed.
Constraints:
- The number of nodes in the list is in the range
[1, 105]. 0 <= Node.val <= 105
Approach overview
Problem Overview: You are given the head of a singly linked list. Nodes are grouped sequentially with sizes 1, 2, 3, 4, and so on. If a group contains an even number of nodes, reverse that group in-place. Odd-length groups remain unchanged. The task is to process the entire list while maintaining correct group boundaries.
Approach 1: Divide and Conquer (O(n) time, O(n) recursion stack)
This approach treats each group as a subproblem. Traverse the list to determine the size of the current group, then isolate that segment. If the segment length is even, reverse it using the standard linked list reversal routine. Recursively process the remaining list and connect the results. The recursion naturally splits the list into independent segments and combines them after processing. Time complexity remains O(n) because each node is visited a constant number of times, while the recursion stack requires up to O(n) space in the worst case.
Approach 2: Greedy Algorithm (O(n) time, O(1) space)
The greedy strategy scans the list once while dynamically forming groups. Maintain a pointer to the start of the current group and track the intended group size (1, 2, 3, ...). Count how many nodes actually exist in the group since the final group may be smaller than expected. If the counted length is even, reverse that segment using the standard iterative reversal with three pointers (prev, curr, next). Otherwise, leave the segment unchanged and simply move forward. Because each node is visited and reversed at most once, the total runtime is O(n) with O(1) extra space.
The key detail is correctly handling the last group. If fewer nodes remain than the expected group size, treat the remaining nodes as the final group and check whether its actual length is even before deciding to reverse.
This problem is a classic exercise in linked list manipulation. Efficient implementations rely on pointer updates rather than extra memory. The greedy traversal also resembles two pointer style pointer management while applying conditional reversal logic similar to many greedy decisions.
Recommended for interviews: The greedy single-pass approach is what most interviewers expect. It demonstrates strong control over pointer manipulation, segment detection, and in-place reversal. The divide and conquer version shows conceptual clarity, but the iterative greedy solution highlights practical linked list mastery and optimal space usage.
Approach 1: Divide and Conquer
In this approach, we tackle the problem by dividing it into smaller sub-problems, solving each sub-problem individually, and then combining their results to get the final solution. This commonly applies in problems where operations are more manageable on smaller datasets or when using recursive strategies such as mergesort, quicksort, or binary search. The efficiency depends on how well we can split the problem and merge the results.
def merge(arr, l, m, r):
n1 = m - l + 1
n2 = r - m
L = arr[l:l + n1]
R = arr[m + 1:m + 1 + n2]
i = j = 0
k = l
while i < len(L) and j < len(R):
if L[i] <= R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
while i < len(L):
arr[k] = L[i]
i += 1
k += 1
while j < len(R):
arr[k] = R[j]
j += 1
k += 1
def merge_sort(arr, l, r):
if l < r:
m = l + (r - l) // 2
merge_sort(arr, l, m)
merge_sort(arr, m + 1, r)
merge(arr, l, m, r)
arr = [12, 11, 13, 5, 6, 7]
merge_sort(arr, 0, len(arr) - 1)
print("Sorted array is:")
print(arr)public class MergeSort {
void merge(int arr[], int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int[] L = new int[n1];
int[] R = new int[n2];
for (int i = 0; i < n1; ++i)
L[i] = arr[l + i];
for (int j = 0; j < n2; ++j)
R[j] = arr[m + 1 + j];
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
void sort(int arr[], int l, int r) {
if (l < r) {
int m = l + (r - l) / 2;
sort(arr, l, m);
sort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
public static void main(String args[]) {
int arr[] = {12, 11, 13, 5, 6, 7};
MergeSort ob = new MergeSort();
ob.sort(arr, 0, arr.length - 1);
System.out.println("Sorted array is");
for (int i = 0; i < arr.length; ++i)
System.out.print(arr[i] + " ");
}
}#include <iostream>
#include <vector>
using namespace std;
void merge(vector<int>& arr, int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
vector<int> L(n1), R(n2);
for (int i = 0; i < n1; ++i)
L[i] = arr[l + i];
for (int j = 0; j < n2; ++j)
R[j] = arr[m + 1 + j];
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j])
arr[k++] = L[i++];
else
arr[k++] = R[j++];
}
while (i < n1)
arr[k++] = L[i++];
while (j < n2)
arr[k++] = R[j++];
}
void mergeSort(vector<int>& arr, int l, int r) {
if (l < r) {
int m = l + (r - l) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
int main() {
vector<int> arr = {12, 11, 13, 5, 6, 7};
mergeSort(arr, 0, arr.size() - 1);
cout << "Sorted array is: \n";
for (auto x : arr)
cout << x << " ";
return 0;
}function merge(arr, l, m, r) {
let n1 = m - l + 1;
let n2 = r - m;
let L = new Array(n1);
let R = new Array(n2);
for (let i = 0; i < n1; i++)
L[i] = arr[l + i];
for (let j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
let i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k++] = L[i++];
}
while (j < n2) {
arr[k++] = R[j++];
}
}
function mergeSort(arr, l, r) {
if (l < r) {
let m = Math.floor(l + (r - l) / 2);
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
let arr = [12, 11, 13, 5, 6, 7];
mergeSort(arr, 0, arr.length - 1);
console.log("Sorted array is: " + arr);#include <stdio.h>
void merge(int arr[], int l, int m, int r) {
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
int L[n1], R[n2];
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
for (j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
void mergeSort(int arr[], int l, int r) {
if (l < r) {
int m = l + (r - l) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int arr_size = sizeof(arr) / sizeof(arr[0]);
mergeSort(arr, 0, arr_size - 1);
printf("Sorted array is: \n");
for (int i = 0; i < arr_size; i++)
printf("%d ", arr[i]);
return 0;
}using System;
class MergeSort {
public void Merge(int[] arr, int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int[] L = new int[n1];
int[] R = new int[n2];
Array.Copy(arr, l, L, 0, n1);
Array.Copy(arr, m + 1, R, 0, n2);
int i = 0, j = 0;
int k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j])
arr[k++] = L[i++];
else
arr[k++] = R[j++];
}
while (i < n1)
arr[k++] = L[i++];
while (j < n2)
arr[k++] = R[j++];
}
public void Sort(int[] arr, int l, int r) {
if (l < r) {
int m = l + (r - l) / 2;
Sort(arr, l, m);
Sort(arr, m + 1, r);
Merge(arr, l, m, r);
}
}
public static void Main() {
int[] arr = { 12, 11, 13, 5, 6, 7 };
MergeSort ob = new MergeSort();
ob.Sort(arr, 0, arr.Length - 1);
Console.WriteLine("Sorted array is");
foreach (var item in arr)
Console.Write(item + " ");
}
}This Python Merge Sort implementation uses list slices for splitting array segments and recursive calls to sort and merge them. This approach leverages Python's strengths in handling lists and recursion expressively and succinctly.
Time Complexity: O(n log n)
Space Complexity: O(n), due to slices used during the merge process.
Approach 2: Greedy Algorithm
Greedy algorithms build a solution piece by piece, always choosing the next piece that offers the most immediate benefit. It doesn't pause to reconsider its previous choices, which can sometimes lead to suboptimal solutions, but they can be very effective for problems like coin change or activity selection where local optimizations lead to global solutions.
def minCoins(coins, V):
coins.sort()
res = 0
i = len(coins) - 1
while i >= 0:
while V >= coins[i]:
V -= coins[i]
res += 1
i -= 1
return res
coins = [1, 2, 5, 10, 20, 50, 100, 500, 1000]
V = 93
print("Minimum coins required is", minCoins(coins, V))import java.util.*;
class CoinChange {
static int minCoins(int coins[], int V) {
Arrays.sort(coins);
int res = 0;
for (int i = coins.length - 1; i >= 0; i--) {
while (V >= coins[i]) {
V -= coins[i];
res++;
}
}
return res;
}
public static void main(String[] args) {
int coins[] = {1, 2, 5, 10, 20, 50, 100, 500, 1000};
int V = 93;
System.out.println("Minimum coins required is " + minCoins(coins, V));
}
}#include <iostream>
#include <vector>
using namespace std;
int minCoins(vector<int>& coins, int V) {
int res = 0;
for (int i = coins.size() - 1; i >= 0; i--) {
while (V >= coins[i]) {
V -= coins[i];
res++;
}
}
return res;
}
int main() {
vector<int> coins = {1, 2, 5, 10, 20, 50, 100, 500, 1000};
int V = 93;
cout << "Minimum coins required is " << minCoins(coins, V);
return 0;
}function minCoins(coins, V) {
coins.sort((a, b) => a - b);
let res = 0;
for (let i = coins.length - 1; i >= 0; i--) {
while (V >= coins[i]) {
V -= coins[i];
res++;
}
}
return res;
}
let coins = [1, 2, 5, 10, 20, 50, 100, 500, 1000];
let V = 93;
console.log("Minimum coins required is " + minCoins(coins, V));#include <stdio.h>
int minCoins(int coins[], int m, int V) {
int res = 0;
for (int i = m - 1; i >= 0; i--) {
while (V >= coins[i]) {
V -= coins[i];
res++;
}
}
return res;
}
int main() {
int coins[] = {1, 2, 5, 10, 20, 50, 100, 500, 1000};
int m = sizeof(coins) / sizeof(coins[0]);
int V = 93;
printf("Minimum coins required is %d", minCoins(coins, m, V));
return 0;
}using System;
class GreedyCoinChange {
static int MinCoins(int[] coins, int V) {
Array.Sort(coins);
int res = 0;
for (int i = coins.Length - 1; i >= 0; i--) {
while (V >= coins[i]) {
V -= coins[i];
res++;
}
}
return res;
}
public static void Main(string[] args) {
int[] coins = { 1, 2, 5, 10, 20, 50, 100, 500, 1000 };
int V = 93;
Console.WriteLine("Minimum coins required is " + MinCoins(coins, V));
}
}This Python solution uses a greedy strategy to solve the coin change problem. The approach prioritizes higher coin values first to reduce the problem space more rapidly, making use of Python's powerful list handling capabilities.
Time Complexity: O(V/d), with V as the value and d as the highest denomination.
Space Complexity: O(1), reflecting limited additional variable use.
Approach 3: Default Approach
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function reverseEvenLengthGroups(head: ListNode | null): ListNode | null {
let nums = [];
let cur = head;
while (cur) {
nums.push(cur.val);
cur = cur.next;
}
const n = nums.length;
for (let i = 0, k = 1; i < n; i += k, k++) {
// 最后一组, 可能出现不足
k = Math.min(n - i, k);
if (!(k & 1)) {
let tmp = nums.splice(i, k);
tmp.reverse();
nums.splice(i, 0, ...tmp);
}
}
cur = head;
for (let num of nums) {
cur.val = num;
cur = cur.next;
}
return head;
}Complexity comparison
| Approach | Complexity |
|---|---|
| Divide and Conquer | Time Complexity: O(n log n) |
| Greedy Algorithm | Time Complexity: O(V/d), with V as the value and d as the highest denomination. |
| Default Approach | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Divide and Conquer | O(n) | O(n) | When recursion simplifies reasoning about independent linked list segments |
| Greedy Iterative Reversal | O(n) | O(1) | Best general solution; optimal for interviews and memory‑constrained environments |
Frequently asked questions
Is Reverse Nodes in Even Length Groups easy or hard?
Reverse Nodes in Even Length Groups is generally classified as a medium difficulty problem. The main challenge is managing group sizes and pointer updates correctly while performing in-place linked list reversal.
Reverse Nodes in Even Length Groups Python/Java solution
Most implementations use an iterative traversal with a helper function to reverse a segment of a linked list. The same logic works across Python, Java, C++, and JavaScript: count group length, conditionally reverse nodes, then reconnect the list segments.
How to solve Reverse Nodes in Even Length Groups in O(n)?
Iterate through the linked list while tracking the expected group size (1, 2, 3, ...). Count the actual number of nodes in each group. If the group length is even, reverse the nodes using the standard three-pointer linked list reversal technique. Continue scanning until the list ends.
What is the best approach for Reverse Nodes in Even Length Groups?
The greedy single-pass approach is the most efficient and commonly expected solution. Traverse the linked list while forming groups of size 1, 2, 3, and so on. If the actual group length is even, reverse that segment in-place using standard linked list reversal. This achieves O(n) time and O(1) extra space.
Is Reverse Nodes in Even Length Groups asked at Google/Amazon/Meta?
Linked list reversal and segmented list manipulation frequently appear in interviews at companies like Amazon, Google, and Meta. Variations of this problem test pointer handling, in-place reversal, and careful boundary management across list segments.
What data structure is used in Reverse Nodes in Even Length Groups?
The problem is built around a singly linked list. The solution relies on pointer manipulation to traverse nodes, detect group boundaries, and reverse segments without using additional data structures.
What is the time complexity of Reverse Nodes in Even Length Groups?
The optimal solution runs in O(n) time because each node is visited a constant number of times during traversal and possible reversal. Space complexity can be O(1) with an iterative greedy approach or O(n) if recursion is used in a divide and conquer implementation.
