Reversing Linked List
Swap nodes in pairs
use dummy node to deal with edge case where the problem involves the operation of the head of the linked list. And we need to use two pointers like pre and cur to implement the swap operation along the way.
public ListNode swapPairs(ListNode head) {
// dummy
// cur, cur.next
// cur != null && cur.next != null, swap two nodes in between,
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode pre = dummy, cur = head;
while (cur != null && cur.next != null) {
ListNode next = cur.next.next, first = cur, second = cur.next;
first.next = next;
second.next = first;
pre.next = second;
pre = first;
cur = next;
}
return dummy.next;
}
Reverse Linked List
this is kind of a technique that we should remember.
public ListNode reverseList(ListNode head) {
ListNode prev = null;
while (head != null) {
ListNode temp = head.next;
head.next = prev;
prev = head;
head = temp;
}
return prev;
}
Reverse Linked List 2
a little bit complex than reverse linked list 1, and we should calculate the steps that cur pointer move carefully.
Before looking at the algorithm, it's important to understand how the link reversal will work and what set of pointers will be required for the same. Let's say we have a linked list consisting of three different nodes,A → B → C
and we want to reverse the links between the nodes and obtainA ← B ← C
.
Suppose we have at our disposal, two pointers. One of them points to the nodeA
and the other one points to the nodeB
. Let's call these pointersprev
andcur
respectively. We can simply use these two pointers to reverse the link betweenA and
B.cur.next = prev
The only problem with this is, we don't have a way of progressing further i.e. once we do this, we can't reach the nodeC
. That's why we need a third pointer that will help us continue the link reversal process. So, we do the following instead.
third = cur.next
cur.next = prev
prev = cur
cur = third
We need two pointers,
prev
andcur
as explained above.The
prev
pointer should be initialized toNone
initially whilecur
is initialized to thehead
of the linked list.We progress the
cur
pointer one step at a time and theprev
pointer follows it.We keep progressing the two pointers in this way until the
cur
pointer reaches the m^{th}mthnode from the beginning of the list. This is the point from where we start reversing our linked list.An important thing to note here is the usage of two additional pointers which we will call as
tail
andcon
. Thetail
pointer points to them^{th}mthnode from the beginning of the linked list and we call it a_tail_pointer since this node becomes the tail of the reverse sublist. Thecon
points to the node one beforem^{th}mthnode and this connects to the new head of the reversed sublist. Let's take a look at a figure to understand these two pointers better.The
tail
and thecon
pointers are set once initially and then used in the end to finish the linked list reversal.Once we reach them^{th}mthnode, we iteratively reverse the links as explained before using the two pointers. We keep on doing this until we are done reversing the link (next pointer) for then^{th}nthnode. At that point, the
prev
pointer would point to then^{th}nthnodeWe use the
con
pointer to attach to theprev
pointer since the node now pointed to by theprev
pointer (then^{th}nthnode from the beginning) will come in place of them^{th}mthnode due after the reversal. Similarly, we will make use of thetail
pointer to connect to the node next to theprev
node i.e.(n+1)^{th}(n+1)thnode from the beginning.
We do the above_iteratively_and we will achieve what the question asks us to do. Let's look at the steps for the algorithm now.
class Solution {
public ListNode reverseBetween(ListNode head, int m, int n) {
if (head == null) return head;
int i = 1;
ListNode prev = null, cur = head;
while (i < m) {
prev = cur;
cur = cur.next;
i++;
}
ListNode before = prev, tail = cur; // before can be null, to be used later
for (; i <= n; ++i) { // the key point is do one more time, cur points to the next un-reversed node.
ListNode next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
if (before != null) {
before.next = prev;
} else {
head = prev;
}
tail.next = cur;
return head;
}
}
How to do it using recursive way?
Rotate Linked List
The idea is that, first round we need to do is to calculate the length of the list. and then do the module operation based on that in order to avoid repetitive rotation.
Then we actually split the original list into two separate lists. So in order to accomplish the rotation process, we need to get several list nodes like the end of the first sublist, the head of the second sublist, and the end of the second sublist.
Finally, we finish rotate process by modify those list node relationship.
public static ListNode rotateRight(ListNode head, int k) {
if (head == null) return head;
ListNode cur = head;
int i = 0;
while (cur != null) {
cur = cur.next;
i++;
}
int offset = k % i;
if (offset == 0) {
return head;
}
cur = head;
int j = 0;
while (j < (i - offset - 1)) {
cur = cur.next;
j++;
}
ListNode newTail = cur;
ListNode newHead = cur.next;
ListNode tail = newHead;
while(tail.next != null) {
tail = tail.next;
}
tail.next = head;
newTail.next = null;
return newHead;
}
Reorder list
In general, there are three steps, get the middle node in the list, reverse the latter part of the list, and merge the two list interleavingly. Time complexity is O(n), and space complexity is O(1).
Note that, if you want to get the middle node, fast and slow pointer is enough, but when need to merge two pointers, you need pre pointer.
public static void reorderList(ListNode head) {
if (head == null) return;
// get the middle node in the list
// get the middle node, just fast and slow pointer enough,
// but if you want to merge two pointers, you need pre pointer.
ListNode fast = head, slow = head, pre = null;
while (fast != null && fast.next != null) {
pre = slow;
slow = slow.next;
fast = fast.next.next;
}
if (pre == null) return;
pre.next = null;
// reverse the latter part of the list
ListNode newAfterHead = reverseList(slow);
// merge two list alternatively
mergeTwoListAlternative(head, newAfterHead);
}
private static ListNode reverseList(ListNode head) {
ListNode pre = null;
while (head != null) {
ListNode next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
private static void mergeTwoListAlternative(ListNode l1, ListNode l2) {
ListNode before = l1, after = l2;
ListNode dummy = new ListNode(-1);
dummy.next = l1;
ListNode cur = dummy;
boolean odd = false;
while (before != null && after != null) {
if (odd) {
cur.next = after;
after = after.next;
} else {
cur.next = before;
before = before.next;
}
odd = !odd;
cur = cur.next;
}
if (before != null) {
cur.next = before;
}
if (after != null) {
cur.next = after;
}
}