Reverse Linked List

Reverse Linked List

·

3 min read

Reverse Linked List

Given the head of a singly linked list, how to reverse with O(1) space complexity?

What we will do is, initialize two pointers, pointer cur poninted to the head and pointer pre pointed to null. Then iterate the while linked list. For every iteration, do the 3 steps:

  1. make cur node points to pre node
  2. move pre forward(points to cur)
  3. move cur forward(points to cur.next)

Take 2->4->6->8->null as an example.

2->4->6->8->null, pre:null, cur:2
null<-2->4->6->8->null, pre:2, cur:4
null<-2<-4->6->8->null, pre:4, cur:6
null<-2<-4<-6->8->null, pre:6, cur:8
null<-2<-4<-6<-8->null, pre:8, cur:null

At the end, we can return the pre node, which will be the new head of the reversed linked list.

function reverseList(head: ListNode | null): ListNode | null {
    let cur = head;
    let pre = null;
    let next = null;

    while (cur !== null) {
        next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }

    return pre;
};

Note above we need to next pointer to help the swap process. We can use the array deconstructing feature to make the process more concise.

function reverseList(head: ListNode | null): ListNode | null {
    let cur = head;
    let pre = null;

    while (cur !== null) {
        [pre, cur.next, cur] = [cur, pre, cur.next];
    }

    return pre;
};

Because this swapping process is the same for every node in the linked list, so we can do it in the recursive way.

function reverseRecursive(pre: ListNode | null, cur: ListNode | null): ListNode | null {
    if (cur === null) {
        return pre;
    }

    [pre, cur.next, cur] = [cur, pre, cur.next]
    return reverseRecursive(pre, cur);
}


function reverseList(head: ListNode | null): ListNode | null {
    return reverseRecursive(null, head);
};

Reverse Linked List II

Now the problem becomes to reverse a sublist from the linked list. Problem signature becomes:

function reverseBetween(head: ListNode | null, left: number, right: number): ListNode | null

As you can see, reverse whole linked list can be seen as one special case for this reverseBetween problem. We can still use the above swapping method to solve this problem. The hard part is that now the array can be split into 3 parts: part before left, part between left and right, part after right. So what we need to do is, reverse part between left and right first, and then somehow make these 3 parts connected properly.

function reverseBetween(head: ListNode | null, left: number, right: number): ListNode | null {
    if (left === right) return head;

    let pre = null;
    let cur = head;
    let count = 1;

    // find the left index node first
    // if count equals left, then cur points to the left index node
    while (cur !== null && count < left) {
        pre = cur;
        cur = cur.next;
        count += 1;
    }

    // these two nodes can be used later to connect the linked list again
    let lastNodeBeforeLeft = pre;
    let lastNodeBetweenLeftAndRight = cur;

    // reverser the part between left and right
    // if count equals right, then its the last swapping operation
    while (count <= right) {
        [pre, cur.next, cur] = [cur, pre, cur.next];
        count += 1;
    }

    // connect the part before left with the part between left and right
    if (lastNodeBeforeLeft === null) {
        head = pre;
    } else {
        lastNodeBeforeLeft.next = pre;
    }

    // connect the part between left and right with the part after right
    lastNodeBetweenLeftAndRight.next = cur;

    return head;
};