{x}
blog image

Delete N Nodes After M Nodes of a Linked List

Solution Explanation: Deleting Nodes in a Linked List

This problem involves traversing a linked list and deleting nodes based on a pattern: keep m nodes, then delete n nodes, repeating this process until the end of the list. The solution uses an iterative approach with two pointers to efficiently manage the deletion.

Approach:

  1. Initialization: Two pointers, pre and cur, are used. pre tracks the node before the group of n nodes to be deleted, and cur iterates through the n nodes to be deleted. Both start at the head of the list.

  2. Keep m nodes: The outer while loop iterates until pre reaches the end of the list. Inside, a for loop advances pre m-1 times, positioning it correctly before the deletion sequence. If pre becomes null before completing m-1 steps, it means there are fewer than m nodes remaining, so the loop ends, and the modified list is returned.

  3. Delete n nodes: Another for loop advances cur n times, traversing the nodes to be deleted. If cur becomes null before completing n steps, it means fewer than n nodes are left after the m nodes, so the loop ends.

  4. Update Links: The crucial step is updating the links to remove the n nodes. pre.next is set to cur.next, effectively bypassing the n nodes. The cur == null ? null : cur.next part handles the edge case where fewer than n nodes remain.

  5. Advance pre: Finally, pre is advanced to pre.next to begin the next iteration of the process.

  6. Return Head: After the while loop completes, the head of the modified linked list is returned.

Time and Space Complexity:

  • Time Complexity: O(N), where N is the number of nodes in the linked list. The algorithm iterates through the list once.
  • Space Complexity: O(1). The algorithm uses a constant amount of extra space for the pointers pre and cur, regardless of the list's size.

Code Examples (with explanations inline):

Python:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
 
class Solution:
    def deleteNodes(self, head: ListNode, m: int, n: int) -> ListNode:
        pre = head  # Pointer before deletion sequence
        while pre:  # Iterate until the end of the list
            for _ in range(m - 1): # Move pre m-1 steps
                if pre:
                    pre = pre.next
                else:
                    return head #Handle edge case of less than m nodes
            if pre is None:  # Check if pre reached the end before completing m-1 steps
                return head
 
            cur = pre  # Pointer for the nodes to be deleted
            for _ in range(n): #Move cur n steps
                if cur:
                    cur = cur.next
                else:
                    break # Handle edge case of less than n nodes after m nodes
 
            pre.next = cur #Update the link to bypass the deleted nodes.
 
            pre = pre.next  # Move pre to the next group of m nodes
 
        return head

The other languages (Java, C++, Go, TypeScript) follow a very similar structure, adapting the syntax and data structures as needed. The core logic of using two pointers to manage the deletion remains consistent across all implementations.