Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes, in the end, should remain as it is.
Follow up:
- Could you solve the problem in
O(1)
extra memory space? - You may not alter the values in the list's nodes, only nodes itself may be changed.
Solutions:
(1) Recursive
Java:
when there exists k nodes to be reversed, reverse list with k+1 node as head then reverse current k group (r
ecursively reverse k nodes from tail to the head)
use 'curr' to be the node previously reversed (or the first node of the next k group at the first time);
use 'head' as the node being removed before 'curr' (at the last time, head=curr);
use 'tmp' to record the head for the next time
public ListNode reverseKGroup(ListNode head, int k) {
ListNode curr = head;
int count = 0;
while (curr != null && count != k) { // find the k+1 node
curr = curr.next;
count++;
}
if (count == k) { // if k+1 node is found
curr = reverseKGroup(curr, k); // reverse list with k+1 node as head
// head - head-pointer to direct part,
// curr - head-pointer to reversed part;
while (count-- > 0) { // reverse current k-group:
ListNode tmp = head.next; // tmp - next head in direct part
head.next = curr; // preappending "direct" head to the reversed list
curr = head; // move head of reversed part to a new node
head = tmp; // move "direct" head to the next node in direct part
}
head = curr;
}
return head;
}
// https://leetcode.com/problems/reverse-nodes-in-k-group/discuss/11423/Short-but-recursive-Java-code-with-comments
(2) Iterative:
Java:
(2.1)
count the number of nodes and save it in 'n'; use a 'dmy' node as the node before head;
reverse k nodes iteratively when n-=k >=k, which will happen n/k times:
use 'tail' to be the tail after being reversed (the head would be the tail after being reversed, so initially set tail=head );
use 'prev' to be the node before the head of the k-node list to be reversed (initiially prev = dmy);
for each iteration(k-1 in total, no need to move the tail), move the node after tail to be the new head [tail.next.next = prev.next], [prev.next = tail.next] and link the tail to next to be moved [tail.next = next];
public ListNode reverseKGroup(ListNode head, int k) {
int n = 0;
for (ListNode i = head; i != null; n++, i = i.next);
ListNode dmy = new ListNode(0);
dmy.next = head;
for(ListNode prev = dmy, tail = head; n >= k; n -= k) {
for (int i = 1; i < k; i++) {
ListNode next = tail.next.next;
tail.next.next = prev.next;
prev.next = tail.next;
tail.next = next;
}
prev = tail;
tail = tail.next;
}
return dmy.next;
}
// by ofLucas https://leetcode.com/problems/reverse-nodes-in-k-group/discuss/11423/Short-but-recursive-Java-code-with-comments
(2.2) Java:
directly use node 'head' to iterate, use i to count the number of the nodes in the list
move the head until i%k==0 at which time head is the kth node of the current k-node list to be reversed
then reverse this k-node list as the photo shows above
public ListNode reverseKGroup(ListNode head, int k) {
ListNode begin;
if (head==null || head.next ==null || k==1)
return head;
ListNode dummyhead = new ListNode(-1);
dummyhead.next = head;
begin = dummyhead;
int i=0;
while (head != null){
i++;
if (i%k == 0){
begin = reverse(begin, head.next);
head = begin.next;
} else {
head = head.next;
}
}
return dummyhead.next;
}
public ListNode reverse(ListNode begin, ListNode end){
ListNode curr = begin.next;
ListNode next, first;
ListNode prev = begin;
first = curr;
while (curr!=end){
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
begin.next = prev;
first.next = curr;
return first;
}
// https://leetcode.com/problems/reverse-nodes-in-k-group/discuss/11440/Non-recursive-Java-solution-and-idea
(2.3) Python
Use a dummy head, and
l, r : define reversing range
pre, cur : used in reversing, standard reverse linked linked list method
jump : used to connect last node in previous k-group to first node in following k-group
reverse k-node list at one time
def reverseKGroup(self, head, k):
dummy = jump = ListNode(0)
dummy.next = l = r = head
while True:
count = 0
while r and count < k: # use r to locate the range
r = r.next
count += 1
if count == k: # if size k satisfied, reverse the inner linked list
pre, cur = r, l
for _ in range(k):
cur.next, cur, pre = pre, cur.next, cur # standard reversing
jump.next, jump, l = pre, l, r # connect two k-groups
else:
return dummy.next
# https://leetcode.com/problems/reverse-nodes-in-k-group/discuss/11491/Succinct-iterative-Python-O(n)-time-O(1)-space
dummy = jump = ListNode(0) means dummy and jump point to the same node initiated as ListNode(0), so before jump is changed, [jump.next = pre] means that node.next points to pre so that dummy.next changed at the first time.