19. Remove Nth Node From End of List

19. Remove Nth Node From End of List

Photo by Aida L on Unsplash

Problem

Given the head of a linked list, remove the n<sup>th</sup> node from the end of the list and return its head. (link)

Example 1:

Input: head = [1,2,3,4,5], n = 2
Output: [1,2,3,5]

Example 2:

Input: head = [1], n = 1
Output: []

Example 3:

Input: head = [1,2], n = 1
Output: [1]

Constraints:

  • The number of nodes in the list is sz.

  • 1 <= sz <= 30

  • 0 <= Node.val <= 100

  • 1 <= n <= sz

Solution

Brute force approach

We must remove the nth node from the end. To achieve this, we must determine the index of this specific node from the beginning. To do so, we first calculate the total number of nodes and subtract 'n' from it to obtain the index of the target node, which is (total nodes - n).

Deleting a node from a linked list involves updating the pointers. To delete a node, our pointer should be positioned just before the target node.

If temp points to the node before the target, then we can delete the target node by using...

temp.next = temp.next.next

Note: This method is not valid for deleting the first node.

Here we iterate through the linked list twice. The first iteration is to determine the length, and the second iteration is for deletion.

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        int count = 0;

        ListNode temp = head;

        while(temp!=null){
            temp = temp.next;
            count+=1;
        }

        //Important check
        if(count==n) return head.next;

        temp = head;

        // Traverse to the node just before the one to delete
        for(int i=0; i<(count-n-1); i++){
            temp = temp.next;
        }

        // No need add any null check first and last node checks already done
        temp.next = temp.next.next;

        return head;
    }
}

Optimal Approach (Slow & Fast pointer)

This method bears resemblance to the brute force approach, but it accomplishes deletion in a single iteration. It employs fast and slow pointers. At any given moment, the fast pointer advances by n nodes ahead. Initially, we move the fast pointer by n nodes, while the slow pointer points to the head. If the fast pointer points to null after n steps, it indicates the need to delete the first node; otherwise, the process continues. Subsequently, we move both pointers until the fast pointer reaches the last node. Once the fast pointer reaches the last node, it signifies that the slow pointer points to the node just before the target. Consequently, we delete the target node using the slow pointer and return the head.

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        int count = 0;

        ListNode fast = head;
        ListNode slow = head;

        for(int i=0; i<n; i++){
            fast = fast.next;
        }

         //Important check
        if(fast==null) return head.next;

        // Traverse to the node just before the one to delete
        while(fast.next!=null){
            fast = fast.next;
            slow = slow.next;
        }

        slow.next = slow.next.next;
        return head;
    }
}