Don't Underestimate the Two Pointers: Removing the N-th Node from the End of a Linked List
Tags: javascript, codenewbie, leetcode, algorithms
Published: 2020-06-11 14:32:46

Today's algorithm is [Remove Nth Node From End of List](https://leetcode.com/problems/remove-nth-node-from-end-of-list/):
>Given a linked list, remove the n-th node from the end of list and return its head.

For example, if the linked list were `1 > 2 > 3 > 4 > 5`, and n = 2, you should return a list with the second node from the end removed, so `1 > 2 > 3 > 5`.

In this post, I'll be discussing my approach to this problem, which is to have two pointers running at the same time. I'll then go over how to code the solution using JavaScript, followed by an example.

## Two Pointers to the Rescue
In linked list problems, two pointers are often a great way to approach the algorithm. The idea behind two pointers is that when one reaches the end of a linked list, the other will be at an important point in the list (you can see another example of using two pointers in a linked list in [this algorithm](https://dev.to/alisabaj/floyd-s-tortoise-and-hare-algorithm-finding-a-cycle-in-a-linked-list-39af)).

In this problem, the way to use two pointers is to have them be `n` steps apart from each other. That way, when the first pointer gets to the end of the linked list, the second pointer will be on the node that is to be removed from the list.

The important thing to remember about singly linked lists is that you can only move in one direction--from the head to the tail. That's why two pointers are so useful: you can keep track of two different points in the list at once.

For this algorithm, I'll create two pointers. Once the first pointer is `n` steps ahead from the head of the list, the second pointer will start. Then, the pointers will continue incrementing, one node at a time, until the first pointer reaches the end of the list (as in, when its value is `null`). When that happens, the second pointer will skip over the next node, because that one is `n` steps from the end of the list.

## Coding the Solution

The first thing to do will be to create a new list, which will essentially be a copy of the inputted list, but won't include the node to be removed. Since the algorithm provides a definition for a singly linked list, in this function we can create a new list with `new ListNode(0)`, and set it equal to the head of the inputted list.

```javascript
function removeNthFromEnd(head, n) {
  let copy = new ListNode(0);
  copy.next = head;
  //...
}
```

Then, we'll want to create two pointers, `firstPointer` and `secondPointer`. We'll initialize them at the start of the list `copy`.

```javascript
function removeNthFromEnd(head, n) {
  let copy = new ListNode(0);
  copy.next = head;
  let firstPointer = copy;
  let secondPointer = copy;
  //...
}
```

Now, we want to keep moving the first pointer through 'copy' until it reaches `n + 1`. To do this, we could use either a for loop or a while loop--just for fun, we'll use a while loop! So, we can create a counter, set it equal to 0, and until the counter reaches `n + 1`, we'll move `firstPointer` on to each next node.

```javascript
function removeNthFromEnd(head, n) {
  let copy = new ListNode(0);
  copy.next = head;
  let firstPointer = copy;
  let secondPointer = copy;
  let counter = 0;
  while (counter < n + 1) {
     firstPointer = firstPointer.next;
     counter++;
  }
  //...
}
```

At this point, we'll want to increment both the first pointer and the second pointer, one node at a time, until the first pointer reaches the end of the list. We know `firstPointer` is at the end of the list when its value is equal to `null`, so we can create a while loop that keeps going as long as the value is not `null`.

```javascript
function removeNthFromEnd(head, n) {
  let copy = new ListNode(0);
  copy.next = head;
  let firstPointer = copy;
  let secondPointer = copy;
  let counter = 0;
  while (counter < n + 1) {
     firstPointer = firstPointer.next;
     counter++;
  }
  while (firstPointer !== null) {
    secondPointer = secondPointer.next;
    firstPointer = firstPointer.next;
  }
  //...
}
```

When the while loop stops executing, we know the first pointer is at the end of the list, which means the second pointer is on the node that's `n` from the end, so we should skip over it. To skip over it, we can set `secondPointer.next` equal to `secondPointer.next.next`.

Finally, we'll want to return the list `copy`, and in order to do so we'll return `copy.next`.

```javascript
function removeNthFromEnd(head, n) {
  let copy = new ListNode(0);
  copy.next = head;
  let firstPointer = copy;
  let secondPointer = copy;
  let counter = 0;
  while (counter < n + 1) {
     firstPointer = firstPointer.next;
     counter++;
  }
  while (firstPointer !== null) {
    secondPointer = secondPointer.next;
    firstPointer = firstPointer.next;
  }
  secondPointer.next = secondPointer.next.next;
  return copy.next;
}
```

## Going Through an Example

Let's use the same example of the list being `1 > 2 > 3 > 4 > 5`, and n = 2. That means that in the end, we'll want to return the list `1 > 2 > 3 > 5`.

We'll start with both `firstPointer` and `secondPointer` pointing at the node 0. When we start, the counter will be 0, and n+1 is 3, so we'll keep moving the `firstPointer` onto the next node (without moving the `secondPointer`) until n = 3. So, after the first time in the while loop, `firstPointer` is at `1`. Then `firstPointer` is at `2`. Then `firstPointer` is at `3`, which is the last time that `firstPointer` will move without `secondPointer`.

![Four images of the same linked list, `1 > 2 > 3 > 4 > 5`. In the first image, a blue `firstPointer` and a red `secondPointer` are both pointing the same space before the list starts. In the second image, `secondPointer` is in the same spot, but `firstPointer` is pointing at `1`. In the third image, `secondPointer` is at the same spot, and `firstPointer` is at `2`. In the final image, `firstPointer` is at `3`, and `secondPointer` is in the same spot.](https://dev-to-uploads.s3.amazonaws.com/i/e7iia9dvw1rdak920hkn.png)

At this point, counter is no longer less than n + 1, so we'll start moving `secondPointer` as well as `firstPointer`, and we'll keep doing this until `firstPointer` is `null`. So `firstPointer` is now on `4` and `secondPointer` is on `1`. Then, `firstPointer` is on `5` and `secondPointer` is on `2`. Finally, `firstPointer` is `null`, and `secondPointer` is on `3`.

![Three images of the same linked list as above. In the first image, `firstPointer` is on `4` and `secondPointer` is on `1`. In the second image, `firstPointer` is on `5`, and `secondPointer` is on `2`. In the third image `firstPointer` is on the empty space after the list (meaning null), and `secondPointer` is on `3`.](https://dev-to-uploads.s3.amazonaws.com/i/h03x9i5zb7rahm8niim9.png)

Because `firstPointer` is `null`, the next node for the `secondPointer` is the node we're skipping over. That means that after `3`, second pointer will go straight to `5`.

![The same linked list as above, except the node `4` has been removed. Now, a very long arrow stretches between `3` and `5`, and `secondPointer` is pointing at `5`.](https://dev-to-uploads.s3.amazonaws.com/i/57uiff8l922ky0eluw6e.png)

What remains is `1 > 2 > 3 > 5`, which is the given list with the 2nd node from the end removed.

--

Please let me know if you have any questions or other solutions to this problem!