19. Remove Nth Node From End of List#
Difficulty: Medium
Link to Problem: To see the Remove Nth Node From End of List problem on LeetCode, click here!
Given the head of a linked list, remove the \(n^{th}\) node from the end of the list and return its head.
Constraints:
The number of nodes in the list is
sz.1 <= sz <= 300 <= Node.val <= 1001 <= n <= sz
Follow up: Could you do this in one pass?
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def removeNthFromEnd(head, n):
# Create a dummy node to handle the case of removing the head node.
dummy = ListNode(0)
dummy.next = head
first = dummy
second = dummy
# Advance the first pointer by n+1 nodes.
for _ in range(n + 1):
first = first.next
# Move both pointers simultaneously until first reaches the end.
while first is not None:
first = first.next
second = second.next
# Remove the nth node by updating the next pointer of the previous node.
second.next = second.next.next
return dummy.next # Return the modified head of the linked list
Explanation:#
We start by defining a
ListNodeclass to represent individual nodes in a linked list. Each node has two attributes:val(the value of the node) andnext(a reference to the next node in the list).The
removeNthFromEndfunction takes the head of a linked list (head) and the valuen, which represents the position from the end of the list of the node to be removed. It returns the modified head of the linked list after the removal.We create a dummy node (
dummy) at the beginning of the list. This dummy node simplifies the code by handling cases where the head of the list needs to be removed.We initialize two pointers,
firstandsecond, both initially pointing to the dummy node.To advance the
firstpointer byn+1nodes, we use aforloop. This positions thefirstpointernnodes ahead of thesecondpointer.We then move both
firstandsecondpointers simultaneously untilfirstreaches the end of the list. This ensures that thesecondpointer ends up pointing to the node that needs to be removed.To remove the nth node from the end, we update the
nextpointer of the node pointed to by thesecondpointer to skip over the node to be removed.Finally, we return
dummy.next, which is the modified head of the linked list without the removed node.Additionally, there are two helper functions:
createLinkedList(values)creates a linked list from a list of values.convertToList(head)converts a linked list back into a list of values.
# Helper function to create a linked list from a list of values.
def createLinkedList(values):
if not values:
return None
head = ListNode(values[0])
current = head
for val in values[1:]:
current.next = ListNode(val)
current = current.next
return head
# Helper function to convert a linked list to a list of values.
def convertToList(head):
result = []
current = head
while current:
result.append(current.val)
current = current.next
return result
Let’s explain the two helper functions:
createLinkedList(values): This function creates a linked list from a list of values.Input:
valuesis a list containing values that you want to insert into the linked list.Output: The function returns the head of the created linked list.
Explanation:
The function starts by checking if the
valueslist is empty. If it is, it returnsNoneto indicate an empty linked list.If the
valueslist is not empty, it creates the first node of the linked list with the value from the first element ofvalues.It then iterates through the remaining elements of
valuesand creates new nodes for each value, connecting them together using thenextattribute to form a linked list.Finally, it returns the head of the linked list, which is the first node created.
convertToList(head): This function converts a linked list into a list of values.Input:
headis the head node of the linked list that you want to convert.Output: The function returns a list containing the values of the nodes in the linked list in order.
Explanation:
The function starts by initializing an empty list,
result, to store the values of the linked list nodes.It then iterates through the linked list starting from the
headnode and appends thevalattribute of each node to theresultlist.The iteration continues until it reaches the end of the linked list (i.e., the
nextattribute of the current node becomesNone).After the iteration is complete, the function returns the
resultlist, which now contains the values of all the nodes in the linked list in the same order as they appear in the linked list.
These helper functions are useful for creating linked lists from lists of values and converting linked lists back into lists of values, making it easier to work with linked list examples and test cases in a more familiar list format.
Test cases#
# Example 1
head1 = createLinkedList([1, 2, 3, 4, 5])
n1 = 2
new_head1 = removeNthFromEnd(head1, n1)
print(convertToList(new_head1))
[1, 2, 3, 5]
# Example 2
head2 = createLinkedList([1])
n2 = 1
new_head2 = removeNthFromEnd(head2, n2)
print(convertToList(new_head2))
[]
# Example 3
head3 = createLinkedList([1, 2])
n3 = 1
new_head3 = removeNthFromEnd(head3, n3)
print(convertToList(new_head3))
[1]
Certainly! Let’s analyze the time and space complexity of the removeNthFromEnd function in isolation:
Time Complexity:
The
removeNthFromEndfunction performs two passes through the linked list. In the worst case, it needs to traverse the entire linked list of length \(N\).The first pass positions the
firstpointer \(n\) nodes ahead of thesecondpointer. This pass takes \(O(N)\) time because it involves iterating through all N nodes.The second pass moves both
firstandsecondpointers simultaneously untilfirstreaches the end of the list. This also takes \(O(N)\) time in the worst case.Therefore, the overall time complexity of the
removeNthFromEndfunction is \(O(N)\).
Space Complexity:
The
removeNthFromEndfunction uses a constant amount of extra space for its variables (e.g.,first,second, anddummy). This space usage does not depend on the size of the linked list.The space complexity is \(O(1)\), indicating that the space used by the function is constant and independent of the size of the input linked list.
In summary, the removeNthFromEnd function has a time complexity of \(O(N)\) and a space complexity of \(O(1)\). It efficiently removes the nth node from the end of the linked list with a single pass through the list and constant extra space usage.