|
export function reverseEvenLengthGroups(head) { |
|
if (!head.next) { |
|
return head; |
|
} |
|
|
|
// we skip the first node since it's an odd group 1, and start with the second node and the second group |
|
// this is the max number of nodes in a group we're currently iterating (can be less nodes if it's the last group) |
|
let currentGroupLength = 2; |
|
// this is the number of nodes we visited in the current group |
|
let currentGroupNodesCount = 0; |
|
|
|
// start node of the current group |
|
let currentGroupStart = head.next; |
|
// node that precedes the starting node of the current group |
|
let currentGroupPrev = head; |
|
|
|
let cursor = currentGroupStart; |
|
|
|
while (cursor) { |
|
currentGroupNodesCount += 1; |
|
|
|
const isLastGroup = cursor.next === null; |
|
|
|
// we should reverse the current group if |
|
// it's the last group (curr.next = null) and we've seen an even number of nodes in the last group |
|
// OR |
|
// it's an even group (2, 4) and we've seen all the nodes of the group |
|
const shouldReverseGroup = |
|
(currentGroupLength % 2 === 0 && |
|
currentGroupNodesCount === currentGroupLength) || |
|
(isLastGroup && currentGroupNodesCount % 2 === 0); |
|
|
|
if (shouldReverseGroup) { |
|
reverseGroup(currentGroupPrev, currentGroupStart, currentGroupNodesCount); |
|
// at this point, currentGroupStart is actually the end node of the reversed group |
|
// reset values to prepare for the next group iteration |
|
currentGroupPrev = currentGroupStart; |
|
currentGroupStart = currentGroupStart.next; |
|
currentGroupNodesCount = 0; |
|
currentGroupLength += 1; |
|
cursor = currentGroupStart; |
|
} else { |
|
cursor = cursor.next; |
|
} |
|
} |
|
|
|
return head; |
|
} |
|
|
|
// reverse group of length nodes, starting from head, |
|
// prev is the node that precedes the head node |
|
function reverseGroup(prev, head, length) { |
|
if (prev) { |
|
prev.next = null; |
|
} |
|
|
|
let l = 0; |
|
let newPrev = null; |
|
let curr = head; |
|
|
|
while (curr && l < length) { |
|
const next = curr.next; |
|
curr.next = newPrev; |
|
newPrev = curr; |
|
curr = next; |
|
l += 1; |
|
} |
|
|
|
// at this point newPrev is the head of the reversed group |
|
// and head is the end node of the reversed group |
|
|
|
if (prev) { |
|
// reconnect the reversed group with the preceding node of the group |
|
prev.next = newPrev; |
|
} |
|
|
|
// reconnect the reversed group with the next node of the group |
|
head.next = curr; |
|
|
|
return newPrev; |
|
} |