Prerequisites
Before attempting this problem, you should be comfortable with:
- Linked List Traversal - Navigating through nodes using next pointers
- Pointer Manipulation - Updating next pointers to skip or remove nodes from the list
- In-Place Modification - Modifying a data structure without using extra space for a new copy
1. Traverse Linked List and Delete In Place
Intuition
The problem asks us to keep the first m nodes, then delete the next n nodes, and repeat this pattern throughout the linked list. Since we are modifying the list in place, we need to track two key positions: the last node we want to keep (the m-th node in each group) and the node that comes after the n deleted nodes. By linking these two positions, we effectively skip over the deleted nodes.
Algorithm
- Initialize two pointers:
currentNodestarting at the head, andlastMNodeto track the last node we want to keep. - While
currentNodeis notnull:- Traverse
mnodes while updatinglastMNodeto point to each node. After this loop,lastMNodepoints to them-th node. - Traverse
nmore nodes. These are the nodes to be deleted. - Link
lastMNode.nexttocurrentNode, effectively removing thennodes from the list.
- Traverse
- Return the head of the modified list.
class Solution:
def deleteNodes(self, head: Optional[ListNode], m: int, n: int) -> Optional[ListNode]:
current_node = head
last_m_node = head
while current_node is not None:
# initialize m_count to m and n_count to n
m_count, n_count = m, n
# traverse m nodes
while current_node is not None and m_count != 0:
last_m_node = current_node
current_node = current_node.next
m_count -= 1
# traverse n nodes
while current_node is not None and n_count != 0:
current_node = current_node.next
n_count -= 1
# delete n nodes
last_m_node.next = current_node
return headTime & Space Complexity
- Time complexity:
- Space complexity:
Where is the length of the linked list pointed by
head.
Common Pitfalls
Forgetting to Handle the End of the List
When traversing through m nodes to keep or n nodes to delete, you must check for null at each step. If the list ends before completing a full cycle, failing to check will cause a null pointer exception.
# Wrong: No null check during traversal
while m_count != 0:
last_m_node = current_node
current_node = current_node.next # Crashes if current_node is None
m_count -= 1
# Correct: Always check for null
while current_node is not None and m_count != 0:
last_m_node = current_node
current_node = current_node.next
m_count -= 1Not Updating the lastMNode Pointer Before Deletion
The lastMNode pointer must be updated during the "keep m nodes" phase, not after. If you forget to track the last kept node, you cannot properly link it to the node after the deleted segment.
# Wrong: lastMNode never gets updated
while current_node is not None and m_count != 0:
current_node = current_node.next
m_count -= 1
# Correct: Update lastMNode before moving forward
while current_node is not None and m_count != 0:
last_m_node = current_node
current_node = current_node.next
m_count -= 1