
Problem Statement
In this problem, we are given the head of a singly linked list. We are tasked to remove the nth node from the end of the list and then return the head of the modified list. The linked list is defined in such a way that each node contains a single value and a reference to the next node.
Examples
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
Approach and Intuition
To tackle this problem, we can follow a two-pointer technique often referred to as the "fast and slow" pointer approach. This method is efficient and requires only a single pass through the linked list. Here’s a detailed breakdown:
Initialization:
- Initialize two pointers,
fast
andslow
. Both are set to start at the head of the linked list.
- Initialize two pointers,
Advance Fast Pointer:
- Move the
fast
pointern
steps ahead. This helps in creating a gap ofn
nodes between thefast
andslow
pointers.
- Move the
Move Both Pointers:
- Continue moving both pointers one step at a time. When the
fast
pointer reaches the end of the list (fast.next
becomesnull
), theslow
pointer will be at the preceding node of the node to be removed.
- Continue moving both pointers one step at a time. When the
Remove nth Node:
- Modify the next pointer of the node where the
slow
pointer is located to skip the node directly after it (which is the nth node from the end).
- Modify the next pointer of the node where the
Special Cases to Consider:
- When the list has only one node or
n
equals the length of the list:- Directly return
null
or the next of the head depending ifn
is1
and the size is1
, because removing the head is necessary.
- Directly return
- List validation:
- Ensure the linked list is not empty before proceeding with any operations.
This approach ensures that the time complexity is linear, O(n), where n is the number of nodes in the linked list, and it does not require any extra space, except for the two-pointer variables, thus achieving O(1) space complexity.
Solutions
- C++
- Java
- C
- JavaScript
- Python
class Solution {
public:
ListNode* deleteNthFromEnd(ListNode* head, int n) {
ListNode prehead(0);
prehead.next = head;
ListNode* lead = &prehead;
ListNode* follow = &prehead;
// Positioning lead pointer n+1 places from the start
for (int i = 1; i <= n + 1; i++) {
lead = lead->next;
}
// Moving both pointers until lead reaches the end
while (lead != NULL) {
lead = lead->next;
follow = follow->next;
}
// Skipping the nth node from end
follow->next = follow->next->next;
return prehead.next;
}
};
The solution provided details an implementation in C++ to remove the Nth node from the end of a singly linked list. The function deleteNthFromEnd
receives the head of the list and the integer n
, denoting the Nth position from the end of the list to be removed.
- Initialize a
prehead
to an auxiliary node with0
as its value and setprehead.next
to point tohead
. This helps simplify edge cases like removing the head. - Create two pointers,
lead
andfollow
, initially set to point to theprehead
. - Increment the
lead
pointern + 1
times. This positions it such that the gap betweenlead
andfollow
isn
nodes. - Traverse the list with both pointers until
lead
reaches the end (NULL
).lead
will move one node at a time.follow
will also move simultaneously withlead
, maintaining the gap.
- After this loop,
follow
points to the node immediately before the Nth node from the end. - To remove the Nth node, set
follow.next
tofollow.next.next
. This skips the desired node, effectively removing it. - Finally, the function returns the next node of
prehead
, which is the potentially new head of the list (if the head was removed).
This solution operates in O(n) time complexity where n is the number of nodes in the list, as it requires a single pass to find and remove the specified node. The space complexity is O(1) since only a fixed number of extra pointers are used.
class Solution {
public ListNode removeNthNodeFromEnd(ListNode startNode, int n) {
ListNode temp = new ListNode(0);
temp.next = startNode;
ListNode front = temp;
ListNode back = temp;
for (int index = 1; index <= n + 1; index++) {
front = front.next;
}
while (front != null) {
front = front.next;
back = back.next;
}
back.next = back.next.next;
return temp.next;
}
}
The provided Java solution addresses the common interview problem of removing the Nth node from the end of a singly linked list. Let's break down the approach:
- Initialize a dummy node (
temp
) and point itsnext
to the starting node (startNode
) of the list. This dummy node helps handle edge cases gracefully, such as removing the head of the list. - Use two pointers,
front
andback
, both starting at the dummy node. This maintains a gap ofn
nodes between them. - Move the
front
pointern + 1
times. This sets up the gap ofn
nodes since after movingn + 1
times,front
isn
nodes ahead ofback
. - Traverse the list until
front
is null. For each step offront
, moveback
one step. This keeps the gap consistent. - After the loop,
back.next
is the node to be removed. Adjust pointers to excludeback.next
from the list. - Return the modified list starting from
temp.next
, skipping the dummy node.
This method efficiently finds and removes the Nth node with a single pass through the list, achieving O(n) time complexity where n is the number of nodes in the list. No extra space is used, yielding O(1) space complexity (ignoring the input). This solution leverages the two-pointer technique, which is effective in problems requiring elements at specific intervals or ends of a list.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* deleteNthNodeFromEnd(struct ListNode* head, int n) {
struct ListNode placeholder;
placeholder.val = 0;
placeholder.next = head;
struct ListNode* fast = &placeholder;
struct ListNode* slow = &placeholder;
// Pushes fast pointer ahead by n nodes to create the proper distance
for (int i = 1; i <= n + 1; i++) fast = fast->next;
// Traverse until fast reaches the tail, moving both pointers
while (fast != NULL) {
fast = fast->next;
slow = slow->next;
}
// Skip the nth node from end
slow->next = slow->next->next;
return placeholder.next;
}
The problem involves removing the Nth node from the end of a singly-linked list in the C programming language. The function deleteNthNodeFromEnd
accomplishes this by first establishing a placeholder node to handle potential edge cases like removing the head node of the list.
Here's the breakdown of the method used in the provided code:
- Begin by creating a placeholder node (
placeholder
) which points to the head of the list. This node acts as a starting point, ensuring the head is easily removable if needed. - Define two pointers,
fast
andslow
, both initially pointing to this placeholder node. - Move the
fast
pointer forward byn+1
positions, creating a separation between thefast
andslow
pointers equal ton
. This ensures that whenfast
pointer reaches the end of the list,slow
pointer is right before the node to be removed. - Traverse through the list until the
fast
pointer reaches the end, moving bothfast
andslow
pointers forward consistently. At each step,fast
moves one node ahead. - Adjust the
next
pointer of the node at theslow
pointer to skip the target node (the Nth node from the end), effectively removing it from the list. - Return the
next
node of the placeholder, which now represents the possibly new head of the list after the removal operation.
This solution is efficient as it only requires a single pass through the list, making it O(n) in terms of time complexity, where n is the number of nodes in the list. The use of a placeholder node simplifies node removal operations, especially at boundary positions like the head of the list.
function deleteNthFromEnd(listHead, nth) {
let prepNode = new ListNode(0);
prepNode.next = listHead;
let lead = prepNode;
let trail = prepNode;
for (let j = 1; j <= nth + 1; j++) {
lead = lead.next;
}
while (lead !== null) {
lead = lead.next;
trail = trail.next;
}
trail.next = trail.next.next;
return prepNode.next;
}
The provided JavaScript function deleteNthFromEnd
efficiently removes the N-th node from the end of a singly linked list. The function takes two arguments: listHead
, which is the head of the linked list, and nth
, which specifies the position from the end of the list of the node to be removed.
Complete the task by following these steps:
- Initialize a new dummy node (
prepNode
) and set itsnext
pointer to the head of the list (listHead
). This dummy node helps handle edge cases such as removing the head node. - Declare two pointer variables,
lead
andtrail
, and initially point them both to the dummy node. - Move the
lead
pointer forward bynth + 1
times. This step creates a gap betweenlead
andtrail
pointers equal tonth + 1
, positioning thelead
pointer ahead so that when it reaches the end of the list,trail
points to the node just before the target node. - Proceed with a loop where both
lead
andtrail
move one node forward untillead
reaches the end of the list. - When the loop completes,
trail.next
is the node to be removed. Bypass this node by updatingtrail.next
totrail.next.next
, effectively removing the target node from the list. - Finally, return the new head of the list, which is
prepNode.next
, as the dummy node should not be part of the returned list.
This approach ensures that the function works in a single pass through the list, making it efficient with a time complexity of O(n) and a spatial complexity of O(1), where n is the number of nodes in the linked list.
class Solution:
def deleteNthFromEnd(self, head_node, n):
"""
:type head_node: ListNode
:type n: int
:rtype: ListNode
"""
buffer_node = ListNode(0)
buffer_node.next = head_node
leading = buffer_node
trailing = buffer_node
# Advances leading pointer by n+1 steps ahead
for i in range(n + 1):
leading = leading.next
# Proceed leading to the end while moving trailing
while leading is not None:
leading = leading.next
trailing = trailing.next
# Skipping the nth node from end
trailing.next = trailing.next.next
return buffer_node.next
This Python function provided, deleteNthFromEnd
, removes the nth node from the end of a singly linked list and returns the modified list. Understand the following key points for implementing the function effectively:
- Initially, a dummy node,
buffer_node
, is created and points to the head of the list. This node helps in edge cases, such as when the list has only one node or when removing the head node itself. - Both
leading
andtrailing
pointers start at the dummy node. - Move the
leading
pointer forward byn + 1
positions to create a gap betweenleading
andtrailing
. This gap reflects the nth position from the end asleading
moves. - Traverse through the list until
leading
points toNone
. During this traverse, bothleading
andtrailing
pointers move forward one step at a time, maintaining the gap. - Once
leading
reaches the end of the list, adjust thenext
pointer of thetrailing
node to skip the nth node from the end, effectively removing it. - Return the list starting from the next node of the dummy, which accounts for any changes made to the head during the process.
Implement these steps to modify any singly linked list by removing a designated node from its end without having to calculate the list's length.
No comments yet.