Remove Nth Node from End of List - Java Solution with O(n) Time Complexity


Given the head of a linked list, remove the nth node from the end of the list and return its head.

 

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

 

Follow up: Could you do this in one pass?

Understanding the Problem

The core challenge of this problem is to remove the nth node from the end of a singly linked list in an efficient manner. This problem is significant in various applications such as managing playlists, task scheduling, and more. A common pitfall is to misunderstand the position of the nth node from the end, especially in edge cases where the list has only one node or when n equals the length of the list.

Approach

To solve this problem, we can use a two-pointer technique to achieve the solution in one pass. The idea is to maintain two pointers, with one pointer starting n nodes ahead of the other. When the first pointer reaches the end of the list, the second pointer will be at the node just before the one we need to remove.

Naive Solution

A naive solution would involve two passes through the list. In the first pass, we count the total number of nodes. In the second pass, we locate the node to be removed. This approach is not optimal as it requires two passes.

Optimized Solution

The optimized solution involves using two pointers. We move the first pointer n steps ahead and then move both pointers simultaneously until the first pointer reaches the end. This ensures that the second pointer is at the node just before the one to be removed.

Algorithm

Here is a step-by-step breakdown of the optimized algorithm:

  1. Initialize two pointers, first and second, both pointing to the head of the list.
  2. Move the first pointer n steps ahead.
  3. Move both pointers simultaneously until the first pointer reaches the end of the list.
  4. The second pointer will now be at the node just before the one to be removed. Adjust the pointers to remove the nth node.
  5. Return the head of the modified list.

Code Implementation

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
public class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        // Create a dummy node to handle edge cases easily
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        
        // Initialize two pointers
        ListNode first = dummy;
        ListNode second = dummy;
        
        // Move the first pointer n steps ahead
        for (int i = 0; i <= n; i++) {
            first = first.next;
        }
        
        // Move both pointers until the first pointer reaches the end
        while (first != null) {
            first = first.next;
            second = second.next;
        }
        
        // Remove the nth node from the end
        second.next = second.next.next;
        
        // Return the head of the modified list
        return dummy.next;
    }
}

Complexity Analysis

The time complexity of this approach is O(n), where n is the number of nodes in the list. This is because we traverse the list with the two pointers in a single pass. The space complexity is O(1) as we are using only a constant amount of extra space.

Edge Cases

Some potential edge cases include:

These edge cases are handled by the algorithm using a dummy node and careful pointer adjustments.

Testing

To test the solution comprehensively, consider the following test cases:

These test cases cover various scenarios, including edge cases and typical cases.

Thinking and Problem-Solving Tips

When approaching such problems, consider the following tips:

Conclusion

In this blog post, we discussed how to remove the nth node from the end of a linked list efficiently using a two-pointer technique. We covered the problem definition, approach, algorithm, code implementation, complexity analysis, edge cases, and testing. Understanding and solving such problems is crucial for improving problem-solving skills and preparing for technical interviews.

Additional Resources

For further reading and practice, consider the following resources: